diff options
author | Tim Watson <tewatson89@gmail.com> | 2019-04-03 14:51:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-03 14:51:13 -0700 |
commit | 0ff25060dae4858a1b60e2277dbd8921de7a6785 (patch) | |
tree | d29d578b9b9d6cfb0999b7a30819d379b85172b7 /platform/android | |
parent | ba2b7a74c420856401d344ff15b27771175c9819 (diff) | |
parent | 0f416fbbde9b146eb28a4bf88586738d12505007 (diff) | |
download | qtlocation-mapboxgl-0ff25060dae4858a1b60e2277dbd8921de7a6785.tar.gz |
Merge pull request #1 from mapbox/masterupstream/friedbunny-external-pr-14135
Merge Master
Diffstat (limited to 'platform/android')
123 files changed, 7977 insertions, 1847 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 7a117f4b2a..55cfd1a6cd 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,48 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +## 7.4.0-alpha.1 - April 3, 2019 + +### Bugs + - Clean up location permissions annotation [#14311](https://github.com/mapbox/mapbox-gl-native/pull/14311) + - Clear camera callbacks' message queue when the map is destroyed [#14292](https://github.com/mapbox/mapbox-gl-native/pull/14292) + - Use a valid gestures focal point when resetting a manager [#14284](https://github.com/mapbox/mapbox-gl-native/pull/14284) + - Disable move gesture detector foreseeing the quickzoom [#14268](https://github.com/mapbox/mapbox-gl-native/pull/14268) + - Remove request render from MapboxMap#onStart [#14245](https://github.com/mapbox/mapbox-gl-native/pull/14245) + - Use TurfMeasurement#distance in LatLng#distanceTo [#14220](https://github.com/mapbox/mapbox-gl-native/pull/14220) + +### Features + - Add pixel dimension annotation to public UiSettings methods [#14281](https://github.com/mapbox/mapbox-gl-native/pull/14281) + - Add #toString override for formatted sections [#14247](https://github.com/mapbox/mapbox-gl-native/pull/14247) + - Harden fetching camera for bounds when padding is excessive [#14221](https://github.com/mapbox/mapbox-gl-native/pull/14221) + - Traverse expression tree when checking for property overrides [#14259](https://github.com/mapbox/mapbox-gl-native/pull/14259) + - Variable label placement [#14184](https://github.com/mapbox/mapbox-gl-native/pull/14184) + +### Build + - Disable binary programs until we fix [#14294]((https://github.com/mapbox/mapbox-gl-native/pull/14298) + - Disable leak canary during instrumentation tests [#14296](https://github.com/mapbox/mapbox-gl-native/pull/14296) + - Remove Android v7 support library [#14265](https://github.com/mapbox/mapbox-gl-native/pull/14265) + +## 7.3.0 - March 28, 2019 + +### Bugs + - Fix MapView reuse issues [#14127](https://github.com/mapbox/mapbox-gl-native/pull/14127) + - Don't call OnSurfaceCreated from the main thread [#14244](https://github.com/mapbox/mapbox-gl-native/pull/14244) + +## 7.3.0-beta.1 - March 20, 2019 + +### Features + - Expose "text-color" option for formatted sections [#14128](https://github.com/mapbox/mapbox-gl-native/pull/14128) + - Expose LocationComponent's layer IDs [#14155](https://github.com/mapbox/mapbox-gl-native/pull/14155) + +### Bugs + - Cache location layer IDs in a set instead of a list [#14141](https://github.com/mapbox/mapbox-gl-native/pull/14141) + - Clear the style object when the map is destroyed [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + - Cache source/layer only when successfully added [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + +### Build + - Bump telemetry version to 4.3.0 [#14140](https://github.com/mapbox/mapbox-gl-native/pull/14140) + ## 7.3.0-alpha.2 - March 13, 2019 ### Features diff --git a/platform/android/LICENSE.md b/platform/android/LICENSE.md index f69b393541..d6f4e65302 100644 --- a/platform/android/LICENSE.md +++ b/platform/android/LICENSE.md @@ -1,11 +1,5 @@ <!-- This file was generated. Use `make android-license` to update. --> ## Additional Mapbox GL licenses -Mapbox GL uses portions of the Android AppCompat Library v7. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Arch-Common. URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -18,18 +12,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox GL uses portions of the Android Lifecycle Extensions. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox GL uses portions of the Android Lifecycle LiveData. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Lifecycle LiveData Core. URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -54,12 +36,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox GL uses portions of the Android Support AnimatedVectorDrawable. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Support Library Annotations. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -90,12 +66,6 @@ License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2. =========================================================================== -Mapbox GL uses portions of the Android Support VectorDrawable. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Converter: Gson. License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -157,6 +127,12 @@ License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== +Mapbox GL uses portions of the ReLinker. +URL: [https://github.com/KeepSafe/ReLinker](https://github.com/KeepSafe/ReLinker) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox GL uses portions of the Retrofit. License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 89937448e9..74c7c4c465 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -8,7 +8,6 @@ dependencies { api dependenciesList.mapboxJavaGeoJSON api dependenciesList.mapboxAndroidGestures implementation dependenciesList.mapboxJavaTurf - implementation dependenciesList.supportAppcompatV7 implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.okhttp3 @@ -23,10 +22,6 @@ dependencies { android { compileSdkVersion androidVersions.compileSdkVersion - // Roboelectric 4.0 required config - // http://robolectric.org/migrating/#migrating-to-40 - testOptions.unitTests.includeAndroidResources = true - defaultConfig { minSdkVersion androidVersions.minSdkVersion targetSdkVersion androidVersions.targetSdkVersion @@ -134,12 +129,16 @@ android { testOptions { unitTests { returnDefaultValues true + + // Roboelectric 4.0 required config + // http://robolectric.org/migrating/#migrating-to-40 includeAndroidResources = true } } buildTypes { debug { + testCoverageEnabled true jniDebuggable true } } @@ -169,4 +168,5 @@ apply from: "${rootDir}/gradle/gradle-checkstyle.gradle" apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle" apply from: "${rootDir}/gradle/gradle-update-vendor-modules.gradle" apply from: "${rootDir}/gradle/android-nitpick.gradle" -apply from: "${rootDir}/gradle/gradle-bintray.gradle"
\ No newline at end of file +apply from: "${rootDir}/gradle/gradle-bintray.gradle" +apply from: "${rootDir}/gradle/jacoco-report.gradle"
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index be4246a903..5f3ea808fa 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=7.3.0-SNAPSHOT +VERSION_NAME=7.4.0-SNAPSHOT # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index 8ae388549e..ce12489b49 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -5,10 +5,14 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.FloatRange; import android.support.annotation.Keep; - import android.support.annotation.NonNull; import android.support.annotation.Nullable; + +import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.constants.GeometryConstants; +import com.mapbox.turf.TurfMeasurement; + +import static com.mapbox.turf.TurfConstants.UNIT_METRES; /** @@ -209,7 +213,8 @@ public class LatLng implements Parcelable { @NonNull public LatLng wrap() { return new LatLng(latitude, wrap(longitude, - GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE)); + GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE) + ); } @@ -218,8 +223,10 @@ public class LatLng implements Parcelable { * <p> * Same formula as used in Core GL (wrap.hpp) * std::fmod((std::fmod((value - min), d) + d), d) + min; - * + * </p> + * <p> * Multiples of max value will be wrapped to max. + * </p> * * @param value Value to wrap * @param min Minimum value @@ -318,24 +325,10 @@ public class LatLng implements Parcelable { * @return distance in meters */ public double distanceTo(@NonNull LatLng other) { - if (latitude == other.latitude && longitude == other.longitude) { - // return 0.0 to avoid a NaN - return 0.0; - } - - final double a1 = Math.toRadians(this.latitude); - final double a2 = Math.toRadians(this.longitude); - final double b1 = Math.toRadians(other.getLatitude()); - final double b2 = Math.toRadians(other.getLongitude()); - - final double cosa1 = Math.cos(a1); - final double cosb1 = Math.cos(b1); - - final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); - final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); - final double t3 = Math.sin(a1) * Math.sin(b1); - final double tt = Math.acos(t1 + t2 + t3); - - return GeometryConstants.RADIUS_EARTH_METERS * tt; + return TurfMeasurement.distance( + Point.fromLngLat(longitude, latitude), + Point.fromLngLat(other.getLongitude(), other.getLatitude()), + UNIT_METRES + ); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index 4e56c6e9c0..b9aa371a47 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -77,9 +77,11 @@ final class LocationCameraController { void initializeOptions(LocationComponentOptions options) { this.options = options; if (options.trackingGesturesManagement()) { - mapboxMap.setGesturesManager(internalGesturesManager, true, true); + if (mapboxMap.getGesturesManager() != internalGesturesManager) { + mapboxMap.setGesturesManager(internalGesturesManager, true, true); + } adjustGesturesThresholds(); - } else { + } else if (mapboxMap.getGesturesManager() != initialGesturesManager) { mapboxMap.setGesturesManager(initialGesturesManager, true, true); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index b97ab75b5e..327ab3c8ed 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -220,7 +220,6 @@ public final class LocationComponent { * @param style the proxy object for current map style. More info at {@link Style} * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style) { activateLocationComponent(context, style, @@ -237,7 +236,6 @@ public final class LocationComponent { * there should be no location engine initialized * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine) { @@ -259,7 +257,6 @@ public final class LocationComponent { * @param locationEngineRequest the location request * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine, @@ -284,7 +281,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine, @@ -309,7 +305,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) { activateLocationComponent(context, style, LocationComponentOptions.createFromAttributes(context, styleRes)); @@ -327,7 +322,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @NonNull LocationComponentOptions options) { @@ -346,7 +340,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @StyleRes int styleRes) { @@ -365,7 +358,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -382,7 +374,6 @@ public final class LocationComponent { * @param locationEngine the engine * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine) { @@ -398,7 +389,6 @@ public final class LocationComponent { * @param locationEngineRequest the location request * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -415,7 +405,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -453,8 +442,7 @@ public final class LocationComponent { * * @param activationOptions a fully built {@link LocationComponentActivationOptions} object */ - public void activateLocationComponent(@NonNull LocationComponentActivationOptions - activationOptions) { + public void activateLocationComponent(@NonNull LocationComponentActivationOptions activationOptions) { LocationComponentOptions options = activationOptions.locationComponentOptions(); if (options == null) { int styleRes = activationOptions.styleRes(); @@ -496,6 +484,7 @@ public final class LocationComponent { * * @param isEnabled true if the plugin should be visible and listen for location updates, false otherwise. */ + @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) public void setLocationComponentEnabled(boolean isEnabled) { checkActivationState(); if (isEnabled) { @@ -954,7 +943,6 @@ public final class LocationComponent { * @return the last known location */ @Nullable - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) public Location getLastKnownLocation() { checkActivationState(); return lastLocation; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index 093c91e799..c0173cb8e8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; /** - * Contains all the constants being used for the Location layer. + * Contains all the constants being used for the {@link LocationComponent}. */ final class LocationComponentConstants { @@ -49,11 +49,31 @@ final class LocationComponentConstants { static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon"; // Layers - static final String SHADOW_LAYER = "mapbox-location-shadow"; - static final String FOREGROUND_LAYER = "mapbox-location-layer"; - static final String BACKGROUND_LAYER = "mapbox-location-stroke-layer"; - static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer"; - static final String BEARING_LAYER = "mapbox-location-bearing-layer"; + + /** + * Layer ID of the location shadow. + */ + public static final String SHADOW_LAYER = "mapbox-location-shadow-layer"; + + /** + * Layer ID of the location foreground icon. + */ + public static final String FOREGROUND_LAYER = "mapbox-location-foreground-layer"; + + /** + * Layer ID of the location background icon. + */ + public static final String BACKGROUND_LAYER = "mapbox-location-background-layer"; + + /** + * Layer ID of the location accuracy. + */ + public static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer"; + + /** + * Layer ID of the location bearing icon. + */ + public static final String BEARING_LAYER = "mapbox-location-bearing-layer"; // Icons static final String FOREGROUND_ICON = "mapbox-location-icon"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index f11acacf31..aa8a82bf6d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -5,6 +5,7 @@ import android.graphics.PointF; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -18,7 +19,6 @@ import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -70,7 +70,8 @@ final class LocationLayerController { private LocationComponentOptions options; private final OnRenderModeChangedListener internalRenderModeChangedListener; - private final List<String> layerMap = new ArrayList<>(); + @VisibleForTesting + final Set<String> layerSet = new HashSet<>(); private Feature locationFeature; private GeoJsonSource locationSource; @@ -112,7 +113,7 @@ final class LocationLayerController { removeLayers(); addLayers(newLayerBelowOption); if (isHidden) { - for (String layerId : layerMap) { + for (String layerId : layerSet) { setLayerVisibility(layerId, false); } } @@ -193,7 +194,7 @@ final class LocationLayerController { void hide() { isHidden = true; - for (String layerId : layerMap) { + for (String layerId : layerSet) { setLayerVisibility(layerId, false); } } @@ -257,14 +258,14 @@ final class LocationLayerController { private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { style.addLayerBelow(layer, idBelowLayer); - layerMap.add(layer.getId()); + layerSet.add(layer.getId()); } private void removeLayers() { - for (String layerId : layerMap) { + for (String layerId : layerSet) { style.removeLayer(layerId); } - layerMap.clear(); + layerSet.clear(); } private void setBearingProperty(@NonNull String propertyId, float bearing) { @@ -351,7 +352,7 @@ final class LocationLayerController { } private void styleScaling(@NonNull LocationComponentOptions options) { - for (String layerId : layerMap) { + for (String layerId : layerSet) { Layer layer = style.getLayer(layerId); if (layer instanceof SymbolLayer) { layer.setProperties( diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java index b3472ac81e..a1fd4e7e3e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java @@ -142,6 +142,14 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M } } + void onDestroy() { + handler.removeCallbacksAndMessages(null); + onCameraMoveStarted.clear(); + onCameraMoveCanceled.clear(); + onCameraMove.clear(); + onCameraIdle.clear(); + } + private static class CameraChangeHandler extends Handler { private WeakReference<CameraChangeDispatcher> dispatcherWeakReference; 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 c9e6e633aa..9473ea7091 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 @@ -74,7 +74,7 @@ final class MapGestureDetector { * User-set focal point. */ @Nullable - private PointF focalPoint; + private PointF constantFocalPoint; private AndroidGesturesManager gesturesManager; @@ -158,7 +158,7 @@ final class MapGestureDetector { /** * Set the gesture focal point. * <p> - * this is the center point used for calculate transformations from gestures, value is + * This is the center point used for calculate transformations from gestures, value is * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. * </p> * @@ -172,22 +172,7 @@ final class MapGestureDetector { focalPoint = uiSettings.getFocalPoint(); } } - this.focalPoint = focalPoint; - } - - /** - * Get the current active gesture focal point. - * <p> - * This could be either the user provided focal point in - * {@link UiSettings#setFocalPoint(PointF)}or <code>null</code>. - * If it's <code>null</code>, gestures will use focal pointed returned by the detector. - * </p> - * - * @return the current active gesture focal point. - */ - @Nullable - PointF getFocalPoint() { - return focalPoint; + this.constantFocalPoint = focalPoint; } /** @@ -357,18 +342,25 @@ final class MapGestureDetector { int action = motionEvent.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { executeDoubleTap = true; + + // disable the move detector in preparation for the quickzoom, + // so that we don't move the map's center slightly before the quickzoom is started (see #14227) + gesturesManager.getMoveGestureDetector().setEnabled(false); } if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { + // re-enabled the move detector + gesturesManager.getMoveGestureDetector().setEnabled(true); + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) { return false; } PointF zoomFocalPoint; // Single finger double tap - if (focalPoint != null) { + if (constantFocalPoint != null) { // User provided focal point - zoomFocalPoint = focalPoint; + zoomFocalPoint = constantFocalPoint; } else { // Zoom in on gesture zoomFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY()); @@ -468,9 +460,6 @@ final class MapGestureDetector { private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener { private final float minimumVelocity; - - @Nullable - private PointF scaleFocalPoint; private boolean quickZoom; ScaleGestureListener(float minimumVelocity) { @@ -496,8 +485,6 @@ final class MapGestureDetector { if (!uiSettings.isQuickZoomGesturesEnabled()) { return false; } - // when quickzoom, disable move gesture - gesturesManager.getMoveGestureDetector().setEnabled(false); } cancelTransitionsIfRequired(); @@ -510,10 +497,7 @@ final class MapGestureDetector { ); } - // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd() - setScaleFocalPoint(detector); - - sendTelemetryEvent(TelemetryConstants.PINCH, scaleFocalPoint); + sendTelemetryEvent(TelemetryConstants.PINCH, getScaleFocalPoint(detector)); notifyOnScaleBeginListeners(detector); @@ -525,11 +509,10 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - setScaleFocalPoint(detector); - float scaleFactor = detector.getScaleFactor(); double zoomBy = getNewZoom(scaleFactor, quickZoom); - transform.zoomBy(zoomBy, scaleFocalPoint); + PointF focalPoint = getScaleFocalPoint(detector); + transform.zoomBy(zoomBy, focalPoint); notifyOnScaleListeners(detector); @@ -538,11 +521,6 @@ final class MapGestureDetector { @Override public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) { - if (quickZoom) { - //if quickzoom, re-enabling move gesture detector - gesturesManager.getMoveGestureDetector().setEnabled(true); - } - if (uiSettings.isIncreaseRotateThresholdWhenScaling()) { // resetting default angle threshold gesturesManager.getRotateGestureDetector().setAngleThreshold( @@ -562,21 +540,23 @@ final class MapGestureDetector { double zoomAddition = calculateScale(velocityXY, detector.isScalingOut()); double currentZoom = transform.getRawZoom(); + PointF focalPoint = getScaleFocalPoint(detector); long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4); - scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime); + scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, focalPoint, animationTime); scheduleAnimator(scaleAnimator); } - private void setScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) { - if (focalPoint != null) { + @NonNull + private PointF getScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) { + if (constantFocalPoint != null) { // around user provided focal point - scaleFocalPoint = focalPoint; + return constantFocalPoint; } else if (quickZoom) { // around center - scaleFocalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); } else { // around gesture - scaleFocalPoint = detector.getFocalPoint(); + return detector.getFocalPoint(); } } @@ -603,14 +583,12 @@ final class MapGestureDetector { } private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - @Nullable - private PointF rotateFocalPoint; private final float minimumScaleSpanWhenRotating; private final float minimumAngularVelocity; private final float defaultSpanSinceStartThreshold; - public RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity, - float defaultSpanSinceStartThreshold) { + RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity, + float defaultSpanSinceStartThreshold) { this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating; this.minimumAngularVelocity = minimumAngularVelocity; this.defaultSpanSinceStartThreshold = defaultSpanSinceStartThreshold; @@ -631,10 +609,7 @@ final class MapGestureDetector { gesturesManager.getStandardScaleGestureDetector().interrupt(); } - // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd() - setRotateFocalPoint(detector); - - sendTelemetryEvent(TelemetryConstants.ROTATION, rotateFocalPoint); + sendTelemetryEvent(TelemetryConstants.ROTATION, getRotateFocalPoint(detector)); notifyOnRotateBeginListeners(detector); @@ -647,13 +622,12 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - setRotateFocalPoint(detector); - // Calculate map bearing value double bearing = transform.getRawBearing() + rotationDegreesSinceLast; // Rotate the map - transform.setBearing(bearing, rotateFocalPoint.x, rotateFocalPoint.y); + PointF focalPoint = getRotateFocalPoint(detector); + transform.setBearing(bearing, focalPoint.x, focalPoint.y); notifyOnRotateListeners(detector); @@ -687,21 +661,24 @@ final class MapGestureDetector { angularVelocity = -angularVelocity; } - rotateAnimator = createRotateAnimator(angularVelocity, animationTime); + PointF focalPoint = getRotateFocalPoint(detector); + rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint); scheduleAnimator(rotateAnimator); } - private void setRotateFocalPoint(@NonNull RotateGestureDetector detector) { - if (focalPoint != null) { + @NonNull + private PointF getRotateFocalPoint(@NonNull RotateGestureDetector detector) { + if (constantFocalPoint != null) { // User provided focal point - rotateFocalPoint = focalPoint; + return constantFocalPoint; } else { // around gesture - rotateFocalPoint = detector.getFocalPoint(); + return detector.getFocalPoint(); } } - private Animator createRotateAnimator(float angularVelocity, long animationTime) { + private Animator createRotateAnimator(float angularVelocity, long animationTime, + @NonNull final PointF animationFocalPoint) { ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f); animator.setDuration(animationTime); animator.setInterpolator(new DecelerateInterpolator()); @@ -710,7 +687,7 @@ final class MapGestureDetector { public void onAnimationUpdate(@NonNull ValueAnimator animation) { transform.setBearing( transform.getRawBearing() + (float) animation.getAnimatedValue(), - rotateFocalPoint.x, rotateFocalPoint.y, + animationFocalPoint.x, animationFocalPoint.y, 0L ); } @@ -802,9 +779,9 @@ final class MapGestureDetector { PointF zoomFocalPoint; // Single finger double tap - if (focalPoint != null) { + if (constantFocalPoint != null) { // User provided focal point - zoomFocalPoint = focalPoint; + zoomFocalPoint = constantFocalPoint; } else { // Zoom in on gesture zoomFocalPoint = detector.getFocalPoint(); 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 f87c6a854a..23ce2bdef0 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 @@ -911,7 +911,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { /** * Called when the map has finished rendering. * - * @param fully true if map is fully rendered, false if fully rendered + * @param fully true if map is fully rendered, false if not fully rendered */ void onDidFinishRenderingMap(boolean fully); } @@ -1257,4 +1257,4 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { public static void setMapStrictModeEnabled(boolean strictModeEnabled) { MapStrictMode.setStrictModeEnabled(strictModeEnabled); } -}
\ No newline at end of file +} 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 f0155bda58..95d5c29b61 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 @@ -128,7 +128,6 @@ public final class MapboxMap { * Called when the hosting Activity/Fragment onStart() method is called. */ void onStart() { - nativeMapView.update(); locationComponent.onStart(); } @@ -174,6 +173,10 @@ public final class MapboxMap { */ void onDestroy() { locationComponent.onDestroy(); + if (style != null) { + style.clear(); + } + cameraChangeDispatcher.onDestroy(); } /** @@ -813,7 +816,7 @@ public final class MapboxMap { public void setStyle(Style.Builder builder, final Style.OnStyleLoaded callback) { locationComponent.onStartLoadingMap(); if (style != null) { - style.onWillStartLoadingMap(); + style.clear(); } if (callback != null) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index cf5961a313..e49126531a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -29,8 +29,6 @@ interface NativeMap { // Lifecycle API // - void update(); - void resizeView(int width, int height); void onLowMemory(); 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 10942d521c..a5f8be788c 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 @@ -136,15 +136,6 @@ final class NativeMapView implements NativeMap { } @Override - public void update() { - if (checkState("update")) { - return; - } - - mapRenderer.requestRender(); - } - - @Override public void resizeView(int width, int height) { if (checkState("resizeView")) { return; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index f14e034816..5c28b55de8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -100,8 +100,8 @@ public class Style { */ public void addSource(@NonNull Source source) { validateState("addSource"); - sources.put(source.getId(), source); nativeMap.addSource(source); + sources.put(source.getId(), source); } /** @@ -172,8 +172,8 @@ public class Style { */ public void addLayer(@NonNull Layer layer) { validateState("addLayer"); - layers.put(layer.getId(), layer); nativeMap.addLayer(layer); + layers.put(layer.getId(), layer); } /** @@ -184,8 +184,8 @@ public class Style { */ public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { validateState("addLayerBelow"); - layers.put(layer.getId(), layer); nativeMap.addLayerBelow(layer, below); + layers.put(layer.getId(), layer); } /** @@ -196,8 +196,8 @@ public class Style { */ public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { validateState("addLayerAbove"); - layers.put(layer.getId(), layer); nativeMap.addLayerAbove(layer, above); + layers.put(layer.getId(), layer); } /** @@ -209,8 +209,8 @@ public class Style { */ public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { validateState("addLayerAbove"); - layers.put(layer.getId(), layer); nativeMap.addLayerAt(layer, index); + layers.put(layer.getId(), layer); } /** @@ -437,10 +437,11 @@ public class Style { // /** - * Called when the underlying map will start loading a new style. This method will clean up this style - * by setting the java sources and layers in a detached state and removing them from core. + * Called when the underlying map will start loading a new style or the map is destroyed. + * This method will clean up this style by setting the java sources and layers + * in a detached state and removing them from core. */ - void onWillStartLoadingMap() { + void clear() { fullyLoaded = false; for (Source source : sources.values()) { if (source != null) { 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 034dc63c35..c671146876 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 @@ -10,6 +10,7 @@ import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.Px; import android.support.annotation.UiThread; import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; @@ -344,7 +345,7 @@ public final class UiSettings { } /** - * Sets the margins of the compass view. Use this to change the distance of the compass from the + * Sets the margins of the compass view in pixels. Use this to change the distance of the compass from the * map view edge. * * @param left The left margin in pixels. @@ -353,42 +354,46 @@ public final class UiSettings { * @param bottom The bottom margin in pixels. */ @UiThread - public void setCompassMargins(int left, int top, int right, int bottom) { + public void setCompassMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(compassView, compassMargins, left, top, right, bottom); } /** - * Returns the left side margin of CompassView + * Returns the left side margin of CompassView in pixels. * * @return The left margin in pixels */ + @Px public int getCompassMarginLeft() { return compassMargins[0]; } /** - * Returns the top side margin of CompassView + * Returns the top side margin of CompassView in pixels. * * @return The top margin in pixels */ + @Px public int getCompassMarginTop() { return compassMargins[1]; } /** - * Returns the right side margin of CompassView + * Returns the right side margin of CompassView in pixels. * * @return The right margin in pixels */ + @Px public int getCompassMarginRight() { return compassMargins[2]; } /** - * Returns the bottom side margin of CompassView + * Returns the bottom side margin of CompassView in pixels. * * @return The bottom margin in pixels */ + @Px public int getCompassMarginBottom() { return compassMargins[3]; } @@ -456,7 +461,7 @@ public final class UiSettings { } /** - * Sets the margins of the logo view. Use this to change the distance of the Mapbox logo from the + * Sets the margins of the logo view in pixels. Use this to change the distance of the Mapbox logo from the * map view edge. * * @param left The left margin in pixels. @@ -464,42 +469,46 @@ public final class UiSettings { * @param right The right margin in pixels. * @param bottom The bottom margin in pixels. */ - public void setLogoMargins(int left, int top, int right, int bottom) { + public void setLogoMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(logoView, logoMargins, left, top, right, bottom); } /** - * Returns the left side margin of the logo + * Returns the left side margin of the logo in pixels. * * @return The left margin in pixels */ + @Px public int getLogoMarginLeft() { return logoMargins[0]; } /** - * Returns the top side margin of the logo + * Returns the top side margin of the logo in pixels. * * @return The top margin in pixels */ + @Px public int getLogoMarginTop() { return logoMargins[1]; } /** - * Returns the right side margin of the logo + * Returns the right side margin of the logo in pixels. * * @return The right margin in pixels */ + @Px public int getLogoMarginRight() { return logoMargins[2]; } /** - * Returns the bottom side margin of the logo + * Returns the bottom side margin of the logo in pixels. * * @return The bottom margin in pixels */ + @Px public int getLogoMarginBottom() { return logoMargins[3]; } @@ -570,14 +579,14 @@ public final class UiSettings { } /** - * Sets the margins of the attribution view. + * Sets the margins of the attribution view in pixels. * * @param left The left margin in pixels. * @param top The top margin in pixels. * @param right The right margin in pixels. * @param bottom The bottom margin in pixels. */ - public void setAttributionMargins(int left, int top, int right, int bottom) { + public void setAttributionMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom); } @@ -599,37 +608,41 @@ public final class UiSettings { } /** - * Returns the left side margin of the attribution view. + * Returns the left side margin of the attribution view in pixels. * * @return The left margin in pixels */ + @Px public int getAttributionMarginLeft() { return attributionsMargins[0]; } /** - * Returns the top side margin of the attribution view. + * Returns the top side margin of the attribution view in pixels. * * @return The top margin in pixels */ + @Px public int getAttributionMarginTop() { return attributionsMargins[1]; } /** - * Returns the right side margin of the attribution view. + * Returns the right side margin of the attribution view in pixels. * * @return The right margin in pixels */ + @Px public int getAttributionMarginRight() { return attributionsMargins[2]; } /** - * Returns the bottom side margin of the logo + * Returns the bottom side margin of the logo in pixels. * * @return The bottom margin in pixels */ + @Px public int getAttributionMarginBottom() { return attributionsMargins[3]; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java index 9d9a7bd2d4..524c1a62ee 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java @@ -2,10 +2,8 @@ package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview; import android.content.Context; import android.opengl.GLSurfaceView; - import android.support.annotation.NonNull; import android.view.SurfaceHolder; - import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser; @@ -25,8 +23,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @NonNull private final GLSurfaceView glSurfaceView; - private boolean requestDestroy; - public GLSurfaceViewMapRenderer(Context context, GLSurfaceView glSurfaceView, String localIdeographFontFamily) { @@ -42,9 +38,8 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @Override public void surfaceDestroyed(SurfaceHolder holder) { - requestDestroy = true; + onSurfaceDestroyed(); } - }); } @@ -60,9 +55,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @Override public void onDestroy() { - if (requestDestroy) { - onSurfaceDestroyed(); - } super.onDestroy(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java index 96d5e9e943..165b15a512 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java @@ -197,7 +197,6 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu if (destroySurface) { eglHolder.destroySurface(); destroySurface = false; - mapRenderer.onSurfaceDestroyed(); break; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index 6262418a29..53c0c1c60f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java @@ -7,10 +7,10 @@ import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -23,7 +23,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; * use {@link com.mapbox.mapboxsdk.maps.UiSettings}. * </p> */ -public final class CompassView extends AppCompatImageView implements Runnable { +public final class CompassView extends ImageView implements Runnable { public static final long TIME_WAIT_IDLE = 500; public static final long TIME_MAP_NORTH_ANIMATION = 150; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java index b88e1885ca..12d1fe46cf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java @@ -1,20 +1,55 @@ package com.mapbox.mapboxsdk.module.telemetry; +import com.google.gson.Gson; + +import com.google.gson.JsonObject; + +import com.google.gson.reflect.TypeToken; import com.mapbox.android.telemetry.Event; import android.os.Bundle; import android.os.Parcel; + import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Locale; /** * Generic Performance Event that can be used for performance measurements. * Customer measurements can be added to the bundle. + * + * Bundle is expected to have following properties: + * "attributes", "counters", and "metadata" with String values. + * + * Attributes: a string representing an array of name/string value pair objects. + * Counters: a string representing an array of name/number value pair objects. + * Metadata is a string representation of a JsonObject with string values. + * + * Here is an example of a Performance event bundle data: + * + * "attributes": [{ "name": "style_id", "value": "mapbox://styles/mapbox/streets-v10"}] + * + * "counters": [{"name": "fps_average", "value": 90.7655486547093}, + * {"name": "fps_deviation", "value": 29.301809631465574}] + * “metadata”: { + * “version”: “9”, + * “screenSize”: “1080x1794”, + * “country”: “US”, + * “device”: “Pixel 2”, + * “abi”: “arm64-v8a”, + * “brand”: “google”, + * “ram”: “3834167296”, + * “os”: “android”, + * “gpu”: “Qualcomm, Adreno (TM) 540, OpenGL ES 3.2 V@313.0 (GIT@7bf2852, Ie32bfa6f6f)“, + * “manufacturer”: “Google” + * } */ public class PerformanceEvent extends Event { - private static final String PERFORMANCE_TRACE = "performance.trace"; + + private static final String PERFORMANCE_TRACE = "mobile.performance_trace"; private final String event; @@ -22,23 +57,36 @@ public class PerformanceEvent extends Event { private final String sessionId; - private final Bundle data; + private final List<Attribute<String>> attributes; + + private final List<Attribute<Double>> counters; + + private final JsonObject metadata; + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US); - PerformanceEvent(String sessionId, Bundle data) { + PerformanceEvent(String sessionId, Bundle bundle) { + this.event = PERFORMANCE_TRACE; this.created = DATE_FORMAT.format(new Date()); this.sessionId = sessionId; - this.data = data; + this.attributes = initList(bundle.getString("attributes"), + new TypeToken<ArrayList<Attribute<String>>>() {}); + this.counters = initList(bundle.getString("counters"), + new TypeToken<ArrayList<Attribute<Double>>>() {}); + this.metadata = initMetaData(bundle.getString("metadata")); } private PerformanceEvent(Parcel in) { this.event = in.readString(); this.created = in.readString(); this.sessionId = in.readString(); - this.data = in.readBundle(); + + this.attributes = initList(in.readString(), new TypeToken<ArrayList<Attribute<String>>>() {}); + this.counters = initList(in.readString(), new TypeToken<ArrayList<Attribute<Double>>>() {}); + this.metadata = initMetaData(in.readString()); } @Override @@ -51,7 +99,30 @@ public class PerformanceEvent extends Event { parcel.writeString(event); parcel.writeString(created); parcel.writeString(sessionId); - parcel.writeBundle(data); + + Gson gson = new Gson(); + + parcel.writeString(gson.toJson(attributes)); + parcel.writeString(gson.toJson(counters)); + + if (metadata != null) { + parcel.writeString(metadata.toString()); + } + } + + private <T> ArrayList<Attribute<T>> initList(String fromString, TypeToken typeToken) { + if (fromString == null || fromString.isEmpty()) { + return new ArrayList<>(); + } + return new Gson().fromJson(fromString, typeToken.getType()); + } + + private JsonObject initMetaData(String fromString) { + if (fromString == null) { + return new JsonObject(); + } else { + return new Gson().fromJson(fromString, JsonObject.class); + } } public static final Creator<PerformanceEvent> CREATOR = new Creator<PerformanceEvent>() { @@ -65,4 +136,15 @@ public class PerformanceEvent extends Event { return new PerformanceEvent[size]; } }; + + + private class Attribute<T> { + private final String name; + private final T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java index 5e021f961e..697a51286f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java @@ -111,8 +111,9 @@ public class TelemetryImpl implements TelemetryDefinition { @Override public void onPerformanceEvent(Bundle data) { - if (data != null && !data.isEmpty()) { - telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data)); + if (data == null) { + data = new Bundle(); } + telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data)); } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index 01ac098d16..8684d7c6f1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -26,7 +26,11 @@ import java.nio.channels.FileChannel; /** * The offline manager is the main entry point for offline-related functionality. + * <p> * It'll help you list and create offline regions. + * </p> + * + * @see <a href="https://docs.mapbox.com/help/troubleshooting/mobile-offline/">Offline Maps Information/</a> */ public class OfflineManager { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java index 1c87b9004b..57cf6271c9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java @@ -323,6 +323,10 @@ public final class Property { // TEXT_JUSTIFY: Text justification options. /** + * The text is aligned towards the anchor position. + */ + public static final String TEXT_JUSTIFY_AUTO = "auto"; + /** * The text is aligned to the left. */ public static final String TEXT_JUSTIFY_LEFT = "left"; @@ -339,6 +343,7 @@ public final class Property { * Text justification options. */ @StringDef({ + TEXT_JUSTIFY_AUTO, TEXT_JUSTIFY_LEFT, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_RIGHT, 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 3d8b921a79..01908b1b0b 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 @@ -2276,6 +2276,46 @@ public class PropertyFactory { } /** + * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue<Float> textRadialOffset(Float value) { + return new LayoutPropertyValue<>("text-radial-offset", value); + } + + /** + * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue<Expression> textRadialOffset(Expression value) { + return new LayoutPropertyValue<>("text-radial-offset", value); + } + + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a String[] value + * @return property wrapper around String[] + */ + public static PropertyValue<String[]> textVariableAnchor(String[] value) { + return new LayoutPropertyValue<>("text-variable-anchor", value); + } + + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a String[] value + * @return property wrapper around String[] + */ + public static PropertyValue<Expression> textVariableAnchor(Expression value) { + return new LayoutPropertyValue<>("text-variable-anchor", value); + } + + /** * Part of the text placed closest to the anchor. * * @param value a String value diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java index ab45cb04f2..75473f0f30 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java @@ -470,6 +470,30 @@ public class SymbolLayer extends Layer { } /** + * Get the TextRadialOffset property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue<Float> getTextRadialOffset() { + checkThread(); + return (PropertyValue<Float>) new PropertyValue("text-radial-offset", nativeGetTextRadialOffset()); + } + + /** + * Get the TextVariableAnchor property + * + * @return property wrapper value around String[] + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue<String[]> getTextVariableAnchor() { + checkThread(); + return (PropertyValue<String[]>) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor()); + } + + /** * Get the TextAnchor property * * @return property wrapper value around String @@ -1187,6 +1211,14 @@ public class SymbolLayer extends Layer { @NonNull @Keep + private native Object nativeGetTextRadialOffset(); + + @NonNull + @Keep + private native Object nativeGetTextVariableAnchor(); + + @NonNull + @Keep private native Object nativeGetTextAnchor(); @NonNull diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java index fb2d361bfc..b76e4f4417 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java @@ -58,4 +58,12 @@ public class Formatted { public int hashCode() { return Arrays.hashCode(formattedSections); } + + @Override + public String toString() { + return "Formatted{" + + "formattedSections=" + + Arrays.toString(formattedSections) + + '}'; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java index a5b0dfbfe8..859fcff378 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java @@ -228,4 +228,14 @@ public class FormattedSection { params.put("text-color", textColor); return new Object[] {text, params}; } + + @Override + public String toString() { + return "FormattedSection{" + + "text='" + text + '\'' + + ", fontScale=" + fontScale + + ", fontStack=" + Arrays.toString(fontStack) + + ", textColor='" + textColor + '\'' + + '}'; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java index 3ef8e93cae..3570aa2c0b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java @@ -13,7 +13,6 @@ import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; -import android.support.v7.content.res.AppCompatResources; import android.view.View; import java.io.ByteArrayOutputStream; @@ -152,7 +151,7 @@ public class BitmapUtils { @Nullable public static Drawable getDrawableFromRes(@NonNull Context context, @DrawableRes int drawableRes, @Nullable @ColorInt Integer tintColor) { - Drawable drawable = AppCompatResources.getDrawable(context, drawableRes); + Drawable drawable = context.getResources().getDrawable(drawableRes); if (drawable == null) { return null; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml index 1adbe7e769..e5cde7e441 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml @@ -7,14 +7,14 @@ android:layout_height="wrap_content" android:contentDescription="@string/mapbox_compassContentDescription"/> - <android.support.v7.widget.AppCompatImageView + <ImageView android:visibility="gone" android:id="@+id/logoView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@null"/> - <android.support.v7.widget.AppCompatImageView + <ImageView android:visibility="gone" android:id="@+id/attributionView" android:layout_width="wrap_content" diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java index 8e47f069c3..862c56a526 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java @@ -175,7 +175,7 @@ public class LatLngTest { LatLng latLng2 = new LatLng(1.0, 1.0); assertEquals("distances should match", latLng1.distanceTo(latLng2), - 157425.53710839353, DELTA); + 157298.7453847275, DELTA); } @Test @@ -186,6 +186,15 @@ public class LatLngTest { assertEquals("distance should match", 0.0, distance, DELTA); } + // Regression test for #14216 + @Test + public void testDistanceToClosePointNotNaN() { + LatLng latLng = new LatLng(40.00599, -105.29261); + LatLng other = new LatLng(40.005990000000025, -105.29260999999997); + double distance = latLng.distanceTo(other); + assertNotEquals(distance, Double.NaN); + } + @Test public void testLocationProvider() { double latitude = 1.2; diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java index 56a8f276a7..a3d54fe221 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java @@ -408,6 +408,7 @@ public class LocationCameraControllerTest { MapboxMap mapboxMap = mock(MapboxMap.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); LocationComponentOptions options = mock(LocationComponentOptions.class); when(options.trackingGesturesManagement()).thenReturn(true); @@ -421,6 +422,7 @@ public class LocationCameraControllerTest { MapboxMap mapboxMap = mock(MapboxMap.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); LocationComponentOptions options = mock(LocationComponentOptions.class); when(options.trackingGesturesManagement()).thenReturn(false); @@ -430,6 +432,34 @@ public class LocationCameraControllerTest { } @Test + public void gesturesManagement_optionNotChangedInitial() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(false); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(initialGesturesManager, true, true); + } + + @Test + public void gesturesManagement_optionNotChangedInternal() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(internalGesturesManager, true, true); + } + + @Test public void onMove_notCancellingTransitionWhileNone() { MapboxMap mapboxMap = mock(MapboxMap.class); when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index 10553700b3..6a44cf1f79 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -39,6 +39,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURA import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -160,6 +161,24 @@ public class LocationLayerControllerTest { } @Test + public void onInitialization_numberOfCachedLayerIdsIsConstant() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + controller.initializeComponents(mapboxMap.getStyle(), options); + + assertEquals(5, controller.layerSet.size()); + } + + @Test public void applyStyle_styleShadowWithValidElevation() { OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); LayerSourceProvider sourceProvider = buildLayerProvider(); @@ -300,22 +319,6 @@ public class LocationLayerControllerTest { LayerSourceProvider sourceProvider = buildLayerProvider(); when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); - Layer bearingLayer = mock(Layer.class); - when(bearingLayer.getId()).thenReturn(BEARING_LAYER); - when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); - Layer foregroundLayer = mock(Layer.class); - when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER); - when(sourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); - Layer backgroundLayer = mock(Layer.class); - when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER); - when(sourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); - Layer shadowLayer = mock(Layer.class); - when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); - when(sourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); - Layer accuracyLayer = mock(Layer.class); - when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); - when(sourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); - LocationComponentOptions options = mock(LocationComponentOptions.class); LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); Bitmap bitmap = mock(Bitmap.class); @@ -606,18 +609,23 @@ public class LocationLayerControllerTest { LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); Layer shadowLayer = mock(Layer.class); + when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); when(layerSourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); Layer backgroundLayer = mock(Layer.class); + when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER); when(layerSourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); Layer foregroundLayer = mock(Layer.class); + when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER); when(layerSourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); Layer bearingLayer = mock(Layer.class); + when(bearingLayer.getId()).thenReturn(BEARING_LAYER); when(layerSourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); Layer accuracyLayer = mock(Layer.class); + when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); when(layerSourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); return layerSourceProvider; } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt index a0873e97ff..2d68612c70 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -15,31 +15,33 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class MapboxMapTest { - private lateinit var mapboxMap: MapboxMap - - private lateinit var nativeMapView: NativeMapView - - private lateinit var transform: Transform - - @Before - fun setup() { - val cameraChangeDispatcher = spyk<CameraChangeDispatcher>() - nativeMapView = mockk(relaxed = true) - transform = mockk(relaxed = true) - mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher) - every { nativeMapView.isDestroyed } returns false - every { nativeMapView.nativePtr } returns 5 - mapboxMap.injectLocationComponent(spyk()) - mapboxMap.setStyle(Style.MAPBOX_STREETS) - mapboxMap.onFinishLoadingStyle() - } - - @Test - fun testTransitionOptions() { - val expected = TransitionOptions(100, 200) - mapboxMap.style?.transition = expected - verify { nativeMapView.transitionOptions = expected } - } + private lateinit var mapboxMap: MapboxMap + + private lateinit var nativeMapView: NativeMapView + + private lateinit var transform: Transform + + private lateinit var cameraChangeDispatcher: CameraChangeDispatcher + + @Before + fun setup() { + cameraChangeDispatcher = spyk() + nativeMapView = mockk(relaxed = true) + transform = mockk(relaxed = true) + mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher) + every { nativeMapView.isDestroyed } returns false + every { nativeMapView.nativePtr } returns 5 + mapboxMap.injectLocationComponent(spyk()) + mapboxMap.setStyle(Style.MAPBOX_STREETS) + mapboxMap.onFinishLoadingStyle() + } + + @Test + fun testTransitionOptions() { + val expected = TransitionOptions(100, 200) + mapboxMap.style?.transition = expected + verify { nativeMapView.transitionOptions = expected } + } @Test fun testMoveCamera() { @@ -51,52 +53,52 @@ class MapboxMapTest { verify { transform.moveCamera(mapboxMap, update, callback) } } - @Test - fun testMinZoom() { - mapboxMap.setMinZoomPreference(10.0) - verify { transform.minZoom = 10.0 } - } - - @Test - fun testMaxZoom() { - mapboxMap.setMaxZoomPreference(10.0) - verify { transform.maxZoom = 10.0 } - } - - @Test - fun testFpsListener() { - val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>() - mapboxMap.onFpsChangedListener = fpsChangedListener - assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener) - } - - @Test - fun testTilePrefetch() { - mapboxMap.prefetchesTiles = true - verify { nativeMapView.prefetchTiles = true } - } - - @Test - fun testCameraForLatLngBounds() { - val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() - mapboxMap.setLatLngBoundsForCameraTarget(bounds) - verify { nativeMapView.setLatLngBounds(bounds) } - } - - @Test(expected = IllegalArgumentException::class) - fun testAnimateCameraChecksDurationPositive() { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) - } - - @Test(expected = IllegalArgumentException::class) - fun testEaseCameraChecksDurationPositive() { - mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) - } - - @Test - fun testGetNativeMapPtr() { - assertEquals(5, mapboxMap.nativeMapPtr) - } + @Test + fun testMinZoom() { + mapboxMap.setMinZoomPreference(10.0) + verify { transform.minZoom = 10.0 } + } + + @Test + fun testMaxZoom() { + mapboxMap.setMaxZoomPreference(10.0) + verify { transform.maxZoom = 10.0 } + } + + @Test + fun testFpsListener() { + val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>() + mapboxMap.onFpsChangedListener = fpsChangedListener + assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener) + } + + @Test + fun testTilePrefetch() { + mapboxMap.prefetchesTiles = true + verify { nativeMapView.prefetchTiles = true } + } + + @Test + fun testCameraForLatLngBounds() { + val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() + mapboxMap.setLatLngBoundsForCameraTarget(bounds) + verify { nativeMapView.setLatLngBounds(bounds) } + } + + @Test(expected = IllegalArgumentException::class) + fun testAnimateCameraChecksDurationPositive() { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test(expected = IllegalArgumentException::class) + fun testEaseCameraChecksDurationPositive() { + mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test + fun testGetNativeMapPtr() { + assertEquals(5, mapboxMap.nativeMapPtr) + } @Test fun testNativeMapIsNotCalledOnStateSave() { @@ -104,4 +106,10 @@ class MapboxMapTest { mapboxMap.onSaveInstanceState(mockk(relaxed = true)) verify { nativeMapView wasNot Called } } + + @Test + fun testCameraChangeDispatcherCleared() { + mapboxMap.onDestroy() + verify { cameraChangeDispatcher.onDestroy() } + } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 22222b0f50..190c279e03 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -9,7 +9,7 @@ android { targetSdkVersion androidVersions.targetSdkVersion versionCode 13 versionName "6.0.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "com.mapbox.mapboxsdk.InstrumentationRunner" } compileOptions { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json new file mode 100644 index 0000000000..5ab289344a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json @@ -0,0 +1,5331 @@ +{ + "version": 8, + "name": "mapbox-gl-native-test-style", + "metadata": { + "mapbox:autocomposite": true, + "mapbox:type": "default", + "mapbox:origin": "streets-v10", + "mapbox:groups": { + "1444934828655.3389": {"name": "Aeroways", "collapsed": true}, + "1444933322393.2852": { + "name": "POI labels (scalerank 1)", + "collapsed": true + }, + "1444855786460.0557": {"name": "Roads", "collapsed": true}, + "1444933575858.6992": { + "name": "Highway shields", + "collapsed": true + }, + "1444934295202.7542": { + "name": "Admin boundaries", + "collapsed": true + }, + "1444856151690.9143": {"name": "State labels", "collapsed": true}, + "1444933721429.3076": {"name": "Road labels", "collapsed": true}, + "1444933358918.2366": { + "name": "POI labels (scalerank 2)", + "collapsed": true + }, + "1444933808272.805": {"name": "Water labels", "collapsed": true}, + "1444933372896.5967": { + "name": "POI labels (scalerank 3)", + "collapsed": true + }, + "1444855799204.86": {"name": "Bridges", "collapsed": true}, + "1444856087950.3635": {"name": "Marine labels", "collapsed": true}, + "1456969573402.7817": {"name": "Hillshading", "collapsed": true}, + "1444862510685.128": {"name": "City labels", "collapsed": true}, + "1444855769305.6016": {"name": "Tunnels", "collapsed": true}, + "1456970288113.8113": {"name": "Landcover", "collapsed": true}, + "1444856144497.7825": {"name": "Country labels", "collapsed": true}, + "1444933456003.5437": { + "name": "POI labels (scalerank 4)", + "collapsed": true + } + }, + "mapbox:sdk-support": { + "js": "0.49.0", + "android": "6.5.0", + "ios": "4.4.0" + } + }, + "center": [0.0, 0.0], + "zoom": 0, + "bearing": 0, + "pitch": 0, + "sources": { + "composite": { + "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/lukaspaczos/cjnkdt02b0b2p2ss40skwpvs1", + "glyphs": "mapbox://fonts/lukaspaczos/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {}, + "paint": { + "background-color": { + "base": 1, + "stops": [ + [11, "hsl(35, 32%, 91%)"], + [13, "hsl(35, 12%, 89%)"] + ] + } + } + }, + { + "id": "landcover_snow", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "filter": ["==", "class", "snow"], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": 0.2, + "fill-antialias": false + } + }, + { + "id": "landcover_wood", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "wood"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_scrub", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "scrub"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_grass", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "grass"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_crop", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "crop"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "national_park", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "filter": ["==", "class", "national_park"], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 0.5]]} + } + }, + { + "id": "hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "hospital"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(340, 37%, 87%)"], + [16, "hsl(340, 63%, 89%)"] + ] + } + } + }, + { + "id": "school", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "school"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(50, 47%, 81%)"], + [16, "hsl(50, 63%, 84%)"] + ] + } + } + }, + { + "id": "park", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "park"], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 1]]} + } + }, + { + "id": "pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "pitch"], + "layout": {}, + "paint": {"fill-color": "hsl(100, 57%, 72%)"} + }, + { + "id": "pitch-line", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "minzoom": 15, + "filter": ["==", "class", "pitch"], + "layout": {"line-join": "miter"}, + "paint": {"line-color": "hsl(75, 57%, 84%)"} + }, + { + "id": "cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "cemetery"], + "layout": {}, + "paint": {"fill-color": "hsl(75, 37%, 81%)"} + }, + { + "id": "industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "industrial"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(230, 15%, 86%)"], + [16, "hsl(230, 29%, 89%)"] + ] + } + } + }, + { + "id": "sand", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "sand"], + "layout": {}, + "paint": {"fill-color": "hsl(60, 46%, 87%)"} + }, + { + "id": "hillshade_highlight_bright", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 94], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": {"stops": [[14, 0.12], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_highlight_med", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 90], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": {"stops": [[14, 0.12], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_faint", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 89], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.05], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_med", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 78], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.05], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_dark", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 67], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.06], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_extreme", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 56], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.06], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "waterway-river-canal", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 8, + "filter": ["in", "class", "canal", "river"], + "layout": { + "line-cap": {"base": 1, "stops": [[0, "butt"], [11, "round"]]}, + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": {"base": 1.3, "stops": [[8.5, 0.1], [20, 8]]}, + "line-opacity": {"base": 1, "stops": [[8, 0], [8.5, 1]]} + } + }, + { + "id": "waterway-small", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 13, + "filter": ["!in", "class", "canal", "river"], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": {"base": 1.35, "stops": [[13.5, 0.1], [20, 3]]}, + "line-opacity": {"base": 1, "stops": [[13, 0], [13.5, 1]]} + } + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(215, 84%, 69%)", + "fill-translate": { + "base": 1.2, + "stops": [[7, [0, 0]], [16, [-1, -1]]] + }, + "fill-translate-anchor": "viewport", + "fill-opacity": 1 + } + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": {"fill-color": "hsl(196, 80%, 70%)"} + }, + { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["==", "class", "land"] + ], + "layout": {}, + "paint": {"fill-color": "hsl(35, 12%, 89%)"} + }, + { + "id": "barrier_line-land-line", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "class", "land"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": {"base": 1.99, "stops": [[14, 0.75], [20, 40]]}, + "line-color": "hsl(35, 12%, 89%)" + } + }, + { + "id": "aeroway-polygon", + "type": "fill", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ + "all", + ["!=", "type", "apron"], + ["==", "$type", "Polygon"] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "fill-opacity": {"base": 1, "stops": [[11, 0], [11.5, 1]]} + } + }, + { + "id": "aeroway-runway", + "type": "line", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "runway"] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[9, 1], [18, 80]]} + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "taxiway"] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[10, 0.5], [18, 20]]} + } + }, + { + "id": "building-line", + "type": "line", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + ["!=", "type", "building:part"], + ["==", "underground", "false"] + ], + "layout": {}, + "paint": { + "line-color": "hsl(35, 6%, 79%)", + "line-width": {"base": 1.5, "stops": [[15, 0.75], [20, 3]]}, + "line-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]} + } + }, + { + "id": "building", + "type": "fill", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + ["!=", "type", "building:part"], + ["==", "underground", "false"] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15, "hsl(35, 11%, 88%)"], + [16, "hsl(35, 8%, 85%)"] + ] + }, + "fill-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]}, + "fill-outline-color": "hsl(35, 6%, 79%)" + } + }, + { + "id": "tunnel-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "tunnel-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "tunnel-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3], + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3], + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-dasharray": [3, 3], + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-dasharray": [3, 3], + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "tunnel"], ["==", "type", "trunk"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "tunnel-path", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "tunnel-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "tunnel"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "tunnel-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 77%, 78%)", + "line-opacity": 1, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 78%)", + "line-opacity": 1, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "tunnel-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [1, 0], + "line-blur": 0 + } + }, + { + "id": "tunnel-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [1, 0], + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "trunk"], ["==", "structure", "tunnel"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 77%, 78%)" + } + }, + { + "id": "tunnel-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-dasharray": [1, 0], + "line-opacity": 1, + "line-color": "hsl(26, 100%, 78%)", + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "ferry"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(205, 73%, 63%)"], + [17, "hsl(230, 73%, 63%)"] + ] + }, + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [[12, [1, 0]], [13, [12, 4]]] + } + } + }, + { + "id": "ferry_auto", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "ferry_auto"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(205, 73%, 63%)"], + [17, "hsl(230, 73%, 63%)"] + ] + }, + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "road-path-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["!in", "type", "crossing", "sidewalk", "steps"], + ["==", "class", "path"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "road-steps-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "steps"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 2], [17, 4.6], [18, 7]] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [1, 0], + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "road-sidewalk-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "type", "crossing", "sidewalk"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 0.75]]} + } + }, + { + "id": "turning-features-outline", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "class", "turning_circle", "turning_loop"] + ], + "layout": { + "icon-image": "turning-circle-outline", + "icon-size": { + "base": 1.5, + "stops": [[14, 0.122], [18, 0.969], [20, 1]] + }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "road-pedestrian-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "road-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "road-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]} + } + }, + { + "id": "road-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]} + } + }, + { + "id": "road-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]} + } + }, + { + "id": "road-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "road-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "road-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "trunk"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": {"base": 1, "stops": [[6, 0], [6.1, 1]]} + } + }, + { + "id": "road-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "road-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "road-sidewalks", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "type", "crossing", "sidewalk"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]} + } + }, + { + "id": "road-path", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["!in", "type", "crossing", "sidewalk", "steps"], + ["==", "class", "path"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "road-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "steps"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "road-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)", + "line-opacity": 1 + } + }, + { + "id": "road-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)", + "line-opacity": 1 + } + }, + { + "id": "road-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "road-pedestrian-polygon-fill", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["==", "structure", "none"], + ["in", "class", "path", "pedestrian"] + ] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [16, "hsl(230, 16%, 94%)"], + [16.25, "hsl(230, 50%, 98%)"] + ] + }, + "fill-outline-color": "hsl(230, 26%, 88%)", + "fill-opacity": 1 + } + }, + { + "id": "road-pedestrian-polygon-pattern", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["==", "structure", "none"], + ["in", "class", "path", "pedestrian"] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "hsl(35, 10%, 83%)", + "fill-pattern": "pedestrian-polygon", + "fill-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]} + } + }, + { + "id": "road-polygon", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["!in", "class", "motorway", "path", "pedestrian", "trunk"], + ["!in", "structure", "bridge", "tunnel"] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "#d6d9e6" + } + }, + { + "id": "road-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "road-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": { + "base": 1, + "stops": [[5, "hsl(35, 32%, 91%)"], [8, "hsl(0, 0%, 100%)"]] + }, + "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]} + } + }, + { + "id": "road-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [[5, "hsl(35, 32%, 91%)"], [7, "hsl(0, 0%, 100%)"]] + }, + "line-opacity": 1 + } + }, + { + "id": "road-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["==", "oneway", "true"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["==", "oneway", "true"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "trunk"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [ + [6, "hsl(0, 0%, 100%)"], + [6.1, "hsl(46, 80%, 60%)"], + [9, "hsl(46, 85%, 67%)"] + ] + } + } + }, + { + "id": "road-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [ + [8, "hsl(26, 87%, 62%)"], + [9, "hsl(26, 100%, 68%)"] + ] + } + } + }, + { + "id": "road-rail", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "road-rail-tracks", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]}, + "line-dasharray": [0.1, 15], + "line-opacity": {"base": 1, "stops": [[13.75, 0], [14, 1]]} + } + }, + { + "id": "level-crossings", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "Point"], + ["==", "class", "level_crossing"] + ], + "layout": { + "icon-size": 1, + "icon-image": "level-crossing", + "icon-allow-overlap": true + }, + "paint": {} + }, + { + "id": "road-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "turning-features", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "class", "turning_circle", "turning_loop"] + ], + "layout": { + "icon-image": "turning-circle", + "icon-size": {"base": 1.5, "stops": [[14, 0.095], [18, 1]]}, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "bridge-path-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[15, 0], [15.25, 1]]} + } + }, + { + "id": "bridge-steps-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 2], [17, 4.6], [18, 7]] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [1, 0], + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "bridge-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "bridge-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "bridge"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]} + } + }, + { + "id": "bridge-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + } + } + }, + { + "id": "bridge-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + } + } + }, + { + "id": "bridge-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-translate": [0, 0] + } + }, + { + "id": "bridge-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-translate": [0, 0] + } + }, + { + "id": "bridge-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "bridge-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "bridge-path", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "bridge-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "bridge-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "bridge-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "bridge"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "bridge-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-street", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "type", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]} + } + }, + { + "id": "bridge-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1 + } + }, + { + "id": "bridge-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-rail", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "bridge-rail-tracks", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]}, + "line-dasharray": [0.1, 15], + "line-opacity": {"base": 1, "stops": [[13.75, 0], [20, 1]]} + } + }, + { + "id": "bridge-trunk_link-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "bridge-motorway_link-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-motorway-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-trunk_link-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-trunk-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "aerialway", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "class", "aerialway"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "hsl(230, 10%, 74%)", + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]], + "layout": {"line-join": "bevel"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [8, "hsl(35, 12%, 89%)"], + [16, "hsl(230, 49%, 90%)"] + ] + }, + "line-width": {"base": 1, "stops": [[7, 3.75], [12, 5.5]]}, + "line-opacity": {"base": 1, "stops": [[7, 0], [8, 0.75]]}, + "line-dasharray": [1, 0], + "line-translate": [0, 0], + "line-blur": {"base": 1, "stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "admin-2-boundaries-bg", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0]], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": {"base": 1, "stops": [[3, 3.5], [10, 8]]}, + "line-color": { + "base": 1, + "stops": [ + [6, "hsl(35, 12%, 89%)"], + [8, "hsl(230, 49%, 90%)"] + ] + }, + "line-opacity": {"base": 1, "stops": [[3, 0], [4, 0.5]]}, + "line-translate": [0, 0], + "line-blur": {"base": 1, "stops": [[3, 0], [10, 2]]} + } + }, + { + "id": "admin-3-4-boundaries", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-dasharray": { + "base": 1, + "stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]] + }, + "line-width": {"base": 1, "stops": [[7, 0.75], [12, 1.5]]}, + "line-opacity": {"base": 1, "stops": [[2, 0], [3, 1]]}, + "line-color": { + "base": 1, + "stops": [ + [3, "hsl(230, 14%, 77%)"], + [7, "hsl(230, 8%, 62%)"] + ] + } + } + }, + { + "id": "admin-2-boundaries", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", 0], + ["==", "maritime", 0] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "hsl(230, 8%, 51%)", + "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]} + } + }, + { + "id": "admin-2-boundaries-dispute", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", 1], + ["==", "maritime", 0] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-dasharray": [1.5, 1.5], + "line-color": "hsl(230, 8%, 51%)", + "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]} + } + }, + { + "id": "housenum-label", + "type": "symbol", + "source": "composite", + "source-layer": "housenum_label", + "minzoom": 17, + "layout": { + "text-field": "{house_num}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-padding": 4, + "text-max-width": 7, + "text-size": 9.5 + }, + "paint": { + "text-color": "hsl(35, 2%, 69%)", + "text-halo-color": "hsl(35, 8%, 85%)", + "text-halo-width": 0.5, + "text-halo-blur": 0 + } + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "composite", + "source-layer": "waterway_label", + "minzoom": 12, + "filter": ["in", "class", "canal", "river"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-max-angle": 30, + "text-size": {"base": 1, "stops": [[13, 12], [18, 16]]} + }, + "paint": { + "text-halo-width": 0.5, + "text-halo-color": "hsl(196, 80%, 70%)", + "text-color": "hsl(230, 48%, 44%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l15", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 17, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 4], + [">=", "localrank", 15] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["<=", "localrank", 14], + ["==", "scalerank", 4] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks_scalerank4", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + ["==", "scalerank", 4], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank3", + "type": "symbol", + "metadata": {"mapbox:group": "1444933372896.5967"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank3", + "type": "symbol", + "metadata": {"mapbox:group": "1444933372896.5967"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["==", "scalerank", 3], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "road-label-small", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "class", + "golf", + "link", + "motorway", + "pedestrian", + "primary", + "secondary", + "street", + "street_limited", + "tertiary", + "trunk" + ], + ["==", "$type", "LineString"] + ], + "layout": { + "text-size": {"base": 1, "stops": [[15, 10], [20, 13]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-halo-blur": 1 + } + }, + { + "id": "road-label-medium", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "in", + "class", + "link", + "pedestrian", + "street", + "street_limited" + ] + ], + "layout": { + "text-size": {"base": 1, "stops": [[11, 10], [20, 14]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "road-label-large", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + "layout": { + "text-size": {"base": 1, "stops": [[9, 10], [20, 16]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "road-shields-black", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "!in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ], + ["<=", "reflen", 6] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]}, + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 7%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "road-shields-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + ["<=", "reflen", 6], + [ + "in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]}, + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "motorway-junction", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "motorway_junction", + "minzoom": 14, + "filter": ["all", ["<=", "reflen", 9], [">", "reflen", 0]], + "layout": { + "text-field": "{ref}", + "text-size": 9, + "icon-image": "motorway-exit-{reflen}", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"] + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "text-translate": [0, 0] + } + }, + { + "id": "poi-scalerank2", + "type": "symbol", + "metadata": {"mapbox:group": "1444933358918.2366"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]}, + "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank2", + "type": "symbol", + "metadata": {"mapbox:group": "1444933358918.2366"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["==", "scalerank", 2], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]}, + "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "rail-label", + "type": "symbol", + "source": "composite", + "source-layer": "rail_station_label", + "minzoom": 12, + "filter": ["!=", "maki", "entrance"], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{network}", + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-offset": [0, 0.85], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "base": 1, + "stops": [[0, ""], [13, "{name_en}"]] + }, + "text-letter-spacing": 0.01, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "text-halo-blur": 0.5 + } + }, + { + "id": "water-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444933808272.805"}, + "source": "composite", + "source-layer": "water_label", + "minzoom": 15, + "filter": ["<=", "area", 10000], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[16, 13], [20, 16]]} + }, + "paint": {"text-color": "hsl(230, 48%, 44%)"} + }, + { + "id": "water-label", + "type": "symbol", + "metadata": {"mapbox:group": "1444933808272.805"}, + "source": "composite", + "source-layer": "water_label", + "minzoom": 5, + "filter": [">", "area", 10000], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[13, 13], [18, 18]]} + }, + "paint": {"text-color": "hsl(230, 48%, 44%)"} + }, + { + "id": "place-residential", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 18, + "filter": [ + "all", + ["all", ["<=", "localrank", 10], ["==", "type", "residential"]], + ["in", "$type", "LineString", "Point", "Polygon"] + ], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933322393.2852"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["<=", "scalerank", 1], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933322393.2852"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["<=", "scalerank", 1] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "airport-label", + "type": "symbol", + "source": "composite", + "source-layer": "airport_label", + "minzoom": 9, + "filter": ["<=", "scalerank", 2], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 12], [18, 18]]}, + "icon-image": {"stops": [[12, "{maki}-11"], [13, "{maki}-15"]]}, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.75], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": {"stops": [[11, "{ref}"], [12, "{name_en}"]]}, + "text-letter-spacing": 0.01, + "text-max-width": 9 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "place-islet-archipelago-aboriginal", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ + "in", + "type", + "aboriginal_lands", + "archipelago", + "islet" + ], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-neighbourhood", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "neighbourhood"], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 3, + "text-size": {"base": 1, "stops": [[12, 11], [16, 16]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-suburb", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "suburb"], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3, + "text-size": {"base": 1, "stops": [[11, 11], [15, 18]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-hamlet", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "hamlet"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[12, 11.5], [15, 16]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 8, + "maxzoom": 15, + "filter": ["==", "type", "village"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[10, 11.5], [16, 18]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-town", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 6, + "maxzoom": 15, + "filter": ["==", "type", "town"], + "layout": { + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 11, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [ + 12, + ["DIN Offc Pro Medium", "Arial Unicode MS Regular"] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7, [0, -0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[7, 11.5], [15, 20]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-island", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": ["==", "type", "island"], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-city-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["!in", "scalerank", 0, 1, 2, 3, 4, 5], + ["==", "type", "city"] + ], + "layout": { + "text-size": {"base": 1, "stops": [[6, 12], [14, 22]]}, + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.2]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-city-md-s", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["==", "type", "city"], + ["in", "ldir", "E", "S", "SE", "SW"], + ["in", "scalerank", 3, 4, 5] + ], + "layout": { + "text-field": "{name_en}", + "icon-image": "dot-10", + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.1]], [8, [0, 0]]] + }, + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]} + }, + "paint": { + "text-halo-width": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-city-md-n", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["==", "type", "city"], + ["in", "ldir", "N", "NE", "NW", "W"], + ["in", "scalerank", 3, 4, 5] + ], + "layout": { + "icon-image": "dot-10", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-s", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + ["<=", "scalerank", 2], + ["==", "type", "city"], + ["in", "ldir", "E", "S", "SE", "SW"] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-n", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + ["<=", "scalerank", 2], + ["==", "type", "city"], + ["in", "ldir", "N", "NE", "NW", "W"] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-opacity": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "marine-label-sm-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [">=", "labelrank", 4] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]}, + "symbol-spacing": {"base": 1, "stops": [[4, 100], [6, 400]]}, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-sm-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": ["all", ["==", "$type", "Point"], [">=", "labelrank", 4]], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-md-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "labelrank", 2, 3] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1.1, "stops": [[2, 12], [5, 20]]}, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-md-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "labelrank", 2, 3] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1.1, "stops": [[2, 14], [5, 20]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-lg-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "labelrank", 1] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-lg-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": ["all", ["==", "$type", "Point"], ["==", "labelrank", 1]], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "state-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 9, + "filter": ["<", "area", 20000], + "layout": { + "text-size": {"base": 1, "stops": [[6, 10], [9, 14]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [6, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-md", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 8, + "filter": ["all", ["<", "area", 80000], [">=", "area", 20000]], + "layout": { + "text-size": {"base": 1, "stops": [[5, 10], [8, 16]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [5, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-lg", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 7, + "filter": [">=", "area", 80000], + "layout": { + "text-size": {"base": 1, "stops": [[4, 10], [7, 18]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-padding": 1, + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [4, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "country-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 10, + "filter": [">=", "scalerank", 5], + "layout": { + "text-field": "{name_en}", + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 0.9, "stops": [[5, 14], [9, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-md", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 8, + "filter": ["in", "scalerank", 3, 4], + "layout": { + "text-field": { + "base": 1, + "stops": [[0, "{code}"], [2, "{name_en}"]] + }, + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[3, 10], [8, 24]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-lg", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 7, + "filter": ["in", "scalerank", 1, 2], + "layout": { + "text-field": "{name_en}", + "text-max-width": {"base": 1, "stops": [[0, 5], [3, 6]]}, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 10], [6, 24]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + } + ], + "created": "2018-10-22T14:13:43.210Z", + "id": "cjnkdt02b0b2p2ss40skwpvs1", + "modified": "2018-10-22T14:14:35.211Z", + "owner": "lukaspaczos", + "visibility": "public", + "draft": false +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt new file mode 100644 index 0000000000..ea48bdc00f --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt @@ -0,0 +1,10 @@ +package com.mapbox.mapboxsdk + +import com.mapbox.mapboxsdk.testapp.MapboxApplication + +class InstrumentationApplication : MapboxApplication() { + override fun initializeLeakCanary(): Boolean { + // do not initialize leak canary during instrumentation tests + return true + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt new file mode 100644 index 0000000000..6873b33262 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk + +import android.app.Application +import android.content.Context +import android.support.test.runner.AndroidJUnitRunner + +class InstrumentationRunner : AndroidJUnitRunner() { + override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application { + return super.newApplication(cl, InstrumentationApplication::class.java.name, context) + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt new file mode 100644 index 0000000000..aeb8863790 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt @@ -0,0 +1,39 @@ +package com.mapbox.mapboxsdk.integration + +import android.content.Context +import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.support.test.InstrumentationRegistry +import android.support.test.uiautomator.* +import org.junit.Before + +const val TIMEOUT_UI_SEARCH_WAIT = 5000L + +abstract class BaseIntegrationTest { + + protected lateinit var device: UiDevice + + @Before + open fun beforeTest() { + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + } +} + +/** + * Launches an activity with FLAG_ACTIVITY_NEW_TASK. + * <p> + * To resume an activity, you need to add a single instance launchmode to your manifest configuration. + * <p> + */ +fun UiDevice.launchActivity(context: Context, clazz: Class<*>) { + val applicationPackage = InstrumentationRegistry.getTargetContext().packageName + val intent = Intent(context, clazz) + intent.addFlags(FLAG_ACTIVITY_NEW_TASK) + InstrumentationRegistry.getContext().startActivity(intent) + wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT) +} + +fun UiDevice.scrollRecyclerViewTo(recycleItem: String) { + val appView = UiScrollable(UiSelector().scrollable(true)) + appView.scrollIntoView(UiSelector().text(recycleItem)) +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt new file mode 100644 index 0000000000..b0f6436bdd --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt @@ -0,0 +1,52 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.support.test.uiautomator.By +import android.support.test.uiautomator.SearchCondition +import android.support.test.uiautomator.UiSelector +import android.support.test.uiautomator.Until +import com.mapbox.mapboxsdk.testapp.R +import com.mapbox.mapboxsdk.testapp.activity.fragment.FragmentBackStackActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import kotlinx.android.synthetic.main.activity_backstack_fragment.view.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates MapFragment integration on the backstack + */ +@RunWith(AndroidJUnit4::class) +class FragmentBackStackTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java) + + @Test + @LargeTest + fun backPressedOnBackStackResumed() { + device.waitForIdle() + clickReplaceFragmentButton() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java) + backPressBackStack() + device.waitForIdle() + } + + private fun clickReplaceFragmentButton() { + device.findObject(UiSelector().description(textDescription)).click() + } + + private fun backPressBackStack() { + device.pressBack() // pops fragment, showing map + device.pressBack() // finish activity + } + + private companion object { + const val textDescription = "btn_change_fragment" + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt new file mode 100644 index 0000000000..f22b5f7c9d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt @@ -0,0 +1,30 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + + +/** + * Regression test that validates reopening an Activity with a GLSurfaceView + */ +@RunWith(AndroidJUnit4::class) +class GLSurfaceViewReopenTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java) + + @Test + @LargeTest + fun reopenSimpleMapActivity() { + device.waitForIdle() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity, SimpleMapActivity::class.java) + device.waitForIdle() + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt new file mode 100644 index 0000000000..945fac677e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates if a GLSurfaceView surface can be recreated without crashing. + */ +@RunWith(AndroidJUnit4::class) +class GLSurfaceViewReuseTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java) + + @Test + @LargeTest + fun scrollRecyclerView() { + device.waitForIdle() + device.scrollRecyclerViewTo("Twenty-one") + device.waitForIdle() + device.scrollRecyclerViewTo("One") + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt new file mode 100644 index 0000000000..941b7ea8dc --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt @@ -0,0 +1,34 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class OrientationChangeTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java) + + @Test + @LargeTest + fun rotateSimpleMap() { + device.setOrientationLeft() + device.waitForIdle() + device.setOrientationNatural() + device.waitForIdle() + device.setOrientationRight() + device.waitForIdle() + device.setOrientationNatural() + device.setOrientationLeft() + device.setOrientationNatural() + device.setOrientationRight() + device.setOrientationNatural() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt new file mode 100644 index 0000000000..44da557904 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt @@ -0,0 +1,33 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import com.mapbox.mapboxsdk.testapp.activity.textureview.TextureViewDebugModeActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.Thread.sleep + +/** + * Regression test that validates reopening an Activity with a TextureView + */ +@RunWith(AndroidJUnit4::class) +class TextureViewReopenTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java) + + @Test + @LargeTest + fun reopenTextureViewDebugActivity() { + device.waitForIdle() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java) + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt new file mode 100644 index 0000000000..5c3d66c462 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.TextureRecyclerViewActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates if a GLSurfaceView surface can be recreated without crashing. + */ +@RunWith(AndroidJUnit4::class) +class TextureViewReuseTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java) + + @Test + @LargeTest + fun scrollRecyclerView() { + device.waitForIdle() + device.scrollRecyclerViewTo("Twenty-one") + device.waitForIdle() + device.scrollRecyclerViewTo("One") + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt new file mode 100644 index 0000000000..b918801296 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt @@ -0,0 +1,38 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.support.test.uiautomator.UiSelector +import com.mapbox.mapboxsdk.testapp.activity.fragment.ViewPagerActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates MapFragment integration with a ViewPager + */ +@RunWith(AndroidJUnit4::class) +class ViewPagerScrollTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java) + + @Test + @LargeTest + fun scrollViewPager() { + for (i in 1..4) { + clickTab(i) + } + + for (i in 3 downTo 0) { + clickTab(i) + } + } + + private fun clickTab(index: Int) { + device.findObject(UiSelector().text("Page $index")).click() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index dde03d8a14..f9827c767e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -82,7 +82,7 @@ class LocationComponentTest : EspressoTest() { val locationEngine = component.locationEngine assertThat(locationEngine, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } @@ -118,7 +118,7 @@ class LocationComponentTest : EspressoTest() { assertThat(locationEngine, notNullValue()) assertThat(componentOptions, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(componentOptions?.accuracyAlpha(), `is`(.5f)) assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE)) } @@ -157,7 +157,7 @@ class LocationComponentTest : EspressoTest() { assertThat(locationEngine, nullValue()) assertThat(componentOptions, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(componentOptions?.accuracyAlpha(), `is`(.5f)) assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE)) } @@ -205,7 +205,7 @@ class LocationComponentTest : EspressoTest() { // Force the first location update component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) // Check if the puck is visible assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false)) @@ -240,7 +240,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(300) // waiting for stale state mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature -> @@ -287,7 +287,7 @@ class LocationComponentTest : EspressoTest() { } component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val feature = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0] assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false)) @@ -329,7 +329,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.addImageFromDrawable("custom-foreground-bitmap", it) mapboxMap.addImageFromDrawable("custom-gps-bitmap", it) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) @@ -360,13 +360,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) component.applyStyle(LocationComponentOptions.builder(context).build()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)) } @@ -395,13 +395,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) component.renderMode = RenderMode.NORMAL - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)) } @@ -430,14 +430,14 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(250) // engaging stale state assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false)) @@ -461,13 +461,13 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true)) @@ -499,7 +499,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature -> feature.forEach { @@ -526,7 +526,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertThat(component.locationEngine, nullValue()) @@ -550,14 +550,14 @@ class LocationComponentTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) assertEquals(point.longitude(), location.longitude, 0.1) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) } } @@ -580,7 +580,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = false mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) component.isLocationComponentEnabled = true - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) } @@ -675,7 +675,7 @@ class LocationComponentTest : EspressoTest() { component.onStart() mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -695,7 +695,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -714,7 +714,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.onStop() component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE).isEmpty(), `is`(true)) } @@ -736,7 +736,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.forceLocationUpdate(location) component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) @@ -760,9 +760,9 @@ class LocationComponentTest : EspressoTest() { component.forceLocationUpdate(location) mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) component.onStop() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) @@ -797,7 +797,7 @@ class LocationComponentTest : EspressoTest() { component.applyStyle(options) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -823,7 +823,7 @@ class LocationComponentTest : EspressoTest() { component.forceLocationUpdate(location) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -839,7 +839,7 @@ class LocationComponentTest : EspressoTest() { override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, style: Style, uiController: UiController, context: Context) { styleChangeIdlingResource.waitForStyle(mapboxMap, MAPBOX_HEAVY_STYLE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) locationComponentActivationOptions = LocationComponentActivationOptions .builder(context, mapboxMap.style!!) @@ -878,13 +878,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f) location.bearing = 92f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish assertEquals(92.0f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f) } @@ -906,7 +906,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING_GPS location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -917,7 +917,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -945,7 +945,7 @@ class LocationComponentTest : EspressoTest() { location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -956,7 +956,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -985,7 +985,7 @@ class LocationComponentTest : EspressoTest() { location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1) @@ -996,7 +996,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1) @@ -1021,7 +1021,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.cameraMode = CameraMode.NONE component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.uiSettings.focalPoint, nullValue()) } @@ -1044,7 +1044,7 @@ class LocationComponentTest : EspressoTest() { val zoom = mapboxMap.cameraPosition.zoom component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1066,7 +1066,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(10.0, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1091,7 +1091,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) component.cameraMode = CameraMode.NONE uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) } @@ -1117,7 +1117,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1142,7 +1142,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) component.cancelZoomWhileTrackingAnimation() uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) } @@ -1165,7 +1165,7 @@ class LocationComponentTest : EspressoTest() { val tilt = mapboxMap.cameraPosition.tilt component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1187,7 +1187,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(30.0, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1212,7 +1212,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) component.cameraMode = CameraMode.NONE uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0) } @@ -1237,7 +1237,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1286,7 +1286,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0))) mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0)) component.isLocationComponentEnabled = true - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt index 37b3e8b802..fb450de527 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -75,7 +75,7 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.renderMode = RenderMode.NORMAL - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(style.getSource(LOCATION_SOURCE), notNullValue()) } @@ -99,7 +99,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -123,7 +123,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.COMPASS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -147,7 +147,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -171,7 +171,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.renderMode = RenderMode.GPS assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false)) @@ -197,7 +197,7 @@ class LocationLayerControllerTest : EspressoTest() { component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) // Check that all layers visibilities are set to none assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false)) @@ -223,7 +223,7 @@ class LocationLayerControllerTest : EspressoTest() { component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) styleChangeIdlingResource.waitForStyle(mapboxMap, Style.LIGHT) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL))) @@ -254,13 +254,13 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build()) component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(150) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) } @@ -279,9 +279,9 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) val options = @@ -291,7 +291,7 @@ class LocationLayerControllerTest : EspressoTest() { .build() component.applyStyle(options) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) } } @@ -338,7 +338,7 @@ class LocationLayerControllerTest : EspressoTest() { show = !show } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -359,7 +359,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(ACCURACY_RADIUS_ANIMATION_DURATION) assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/, @@ -386,7 +386,7 @@ class LocationLayerControllerTest : EspressoTest() { val zoom = 16.0 mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(target, zoom), 300) uiController.loopMainThreadForAtLeast(300) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1 @@ -418,7 +418,7 @@ class LocationLayerControllerTest : EspressoTest() { val target = LatLng(location) val zoom = 16.0 mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(target, zoom)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1 && Math.abs(target.latitude - mapboxMap.cameraPosition.target.latitude) < 0.1 @@ -445,7 +445,7 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.applyStyle(LocationComponentOptions.builder(context).layerBelow("road-label").build()) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt deleted file mode 100644 index 98b251027f..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.mapbox.mapboxsdk.maps - -import android.content.Intent -import android.support.test.InstrumentationRegistry -import android.support.test.filters.SdkSuppress -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.* -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.lang.Thread.sleep - -private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp" -private const val LAUNCH_TIMEOUT = 5000L - -@RunWith(AndroidJUnit4::class) -@SdkSuppress(minSdkVersion = 18) -class GLSurfaceViewReopenTest { - - private lateinit var device: UiDevice - - @Before - fun startSimpleMapActivityFromHomeScreen() { - // Initialize UiDevice instance - device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - // Start from the home screen - device.pressHome() - - // Wait for launcher - val launcherPackage: String = device.launcherPackageName - assertThat(launcherPackage, notNullValue()) - device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT) - - // Launch the app - val context = InstrumentationRegistry.getInstrumentation().context - val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply { - // Clear out any previous instances - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - context.startActivity(intent) - - // Wait for the app to appear - device.wait( - Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), - LAUNCH_TIMEOUT - ) - - // open SimpleMapActivity - device.findObject(UiSelector().text("Simple Map")).clickAndWaitForNewWindow() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - } - - @Test - fun reopenSimpleMapActivity() { - // return to home screen - device.pressHome() - - // press recents apps button - device.pressRecentApps() - - // click to reopen app - device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - sleep(LAUNCH_TIMEOUT) - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java index b56d267b81..c8737e2802 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.maps; +import android.support.test.annotation.UiThreadTest; import android.support.test.runner.AndroidJUnit4; import com.mapbox.mapboxsdk.Mapbox; import org.junit.Test; @@ -16,6 +17,7 @@ public class MapboxTest { private static final String ACCESS_TOKEN_2 = "pk.0000000002"; @Test + @UiThreadTest public void testConnected() { assertTrue(Mapbox.isConnected()); @@ -31,6 +33,7 @@ public class MapboxTest { } @Test + @UiThreadTest public void setAccessToken() { String realToken = Mapbox.getAccessToken(); Mapbox.setAccessToken(ACCESS_TOKEN); 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 deleted file mode 100644 index 14a2c3bdbf..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import com.mapbox.mapboxsdk.testapp.activity.BaseTest; -import com.mapbox.mapboxsdk.testapp.activity.camera.CameraAnimationTypeActivity; -import org.junit.Test; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscapeReverse; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortraitReverse; - -public class OrientationTest extends BaseTest { - - @Test - public void testChangeDeviceOrientation() { - onView(isRoot()).perform(orientationLandscape()); - waitAction(2200); - onView(isRoot()).perform(orientationPortrait()); - waitAction(2500); - onView(isRoot()).perform(orientationLandscapeReverse()); - waitAction(500); - onView(isRoot()).perform(orientationPortraitReverse()); - waitAction(1250); - onView(isRoot()).perform(orientationLandscape()); - waitAction(750); - onView(isRoot()).perform(orientationPortrait()); - waitAction(950); - onView(isRoot()).perform(orientationLandscapeReverse()); - onView(isRoot()).perform(orientationPortraitReverse()); - onView(isRoot()).perform(orientationLandscape()); - onView(isRoot()).perform(orientationPortrait()); - } - - @Override - protected Class getActivityClass() { - return CameraAnimationTypeActivity.class; - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt deleted file mode 100644 index cd139ccc40..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.mapbox.mapboxsdk.maps - -import android.content.Intent -import android.support.test.InstrumentationRegistry -import android.support.test.filters.SdkSuppress -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.* -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.lang.Thread.sleep -import android.support.test.uiautomator.UiSelector -import android.support.test.uiautomator.UiScrollable - -private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp" -private const val LAUNCH_TIMEOUT = 5000L - -@RunWith(AndroidJUnit4::class) -@SdkSuppress(minSdkVersion = 18) -class TextureViewReopenTest { - - private lateinit var device: UiDevice - - @Before - fun startSimpleMapActivityFromHomeScreen() { - // Initialize UiDevice instance - device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - // Start from the home screen - device.pressHome() - - // Wait for launcher - val launcherPackage: String = device.launcherPackageName - assertThat(launcherPackage, notNullValue()) - device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT) - - // Launch the app - val context = InstrumentationRegistry.getInstrumentation().context - val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply { - // Clear out any previous instances - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - context.startActivity(intent) - - // Wait for the app to appear - device.wait( - Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), - LAUNCH_TIMEOUT - ) - - // open TextureView debug activity - val appView = UiScrollable(UiSelector().scrollable(true)) - appView.scrollIntoView(UiSelector().text("TextureView debug")) - device.findObject(UiSelector().text("TextureView debug")).clickAndWaitForNewWindow() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - } - - @Test - fun reopenTextureViewDebugActivity() { - // return to home screen - device.pressHome() - - // press recent apps button - device.pressRecentApps() - - // click to reopen app - device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - sleep(LAUNCH_TIMEOUT) - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt index 4866812e67..139695461d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt @@ -1,25 +1,27 @@ -package com.mapbox.mapboxsdk.testapp.maps +package com.mapbox.mapboxsdk.maps import android.graphics.PointF import android.support.test.espresso.UiController import com.mapbox.mapboxsdk.camera.CameraUpdateFactory import com.mapbox.mapboxsdk.geometry.LatLng -import com.mapbox.mapboxsdk.maps.MapView -import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest -import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity + +import com.mapbox.mapboxsdk.testapp.activity.BaseTest +import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test -class VisibleRegionTest : EspressoTest() { +class VisibleRegionTest : BaseTest() { - private lateinit var mapView: MapView + override fun getActivityClass(): Class<*> { + return PixelTestActivity::class.java + } - override fun beforeTest() { + override + fun beforeTest() { super.beforeTest() - mapView = (rule.activity as EspressoTestActivity).mapView + mapView = (rule.activity as PixelTestActivity).mapView } @Test @@ -263,9 +265,9 @@ class VisibleRegionTest : EspressoTest() { @Test fun paddedTopVisibleRegionOverDatelineTest() { validateTestSetup() - invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap -> mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) - + ui.loopMainThreadForAtLeast(5000) val latLngs = listOf( mapboxMap.getLatLngFromScreenCoords(0f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), @@ -299,7 +301,7 @@ class VisibleRegionTest : EspressoTest() { mapboxMap.getLatLngFromScreenCoords(0f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f) - .also { it.longitude += 360 }, + .also { it.longitude += 360 }, mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f) .also { it.longitude += 360 }, mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()) @@ -355,11 +357,11 @@ class VisibleRegionTest : EspressoTest() { mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0)) val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; val latLngs = listOf( - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) ) @@ -371,29 +373,29 @@ class VisibleRegionTest : EspressoTest() { } } - @Test - fun visibleRotatedRegionOverDatelineTest() { - validateTestSetup() - invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) - val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; - val latLngs = listOf( - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f) - .also { it.longitude += 360 }, - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) - ) - - - for (bearing in 45 until 360 step 45) { - mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())); - val visibleRegion = mapboxMap.projection.visibleRegion - assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) }) - } - } + @Test + fun visibleRotatedRegionOverDatelineTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) + val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f) + .also { it.longitude += 360 }, + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + ) + + + for (bearing in 45 until 360 step 45) { + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())); + val visibleRegion = mapboxMap.projection.visibleRegion + assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) }) + } } + } private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng { return this.projection.fromScreenLocation(PointF(x, y)) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java new file mode 100644 index 0000000000..6f256b4e56 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java @@ -0,0 +1,188 @@ +package com.mapbox.mapboxsdk.module.telemetry; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mapbox.mapboxsdk.Mapbox; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(AndroidJUnit4.class) +public class PerformanceEventTest { + + @Test + public void checksPerformanceEventWithMetaData() throws Exception { + PerformanceEvent event = obtainPerformanceEvent(); + assertNotNull(event); + + Parcel parcel = Parcel.obtain(); + + event.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel); + assertNotNull(newPerfEvent); + + compare(event, newPerfEvent, "attributes", "style_id"); + compare(event, newPerfEvent, "counters", "int_value"); + compare(event, newPerfEvent, "counters", "long_value"); + compare(event, newPerfEvent, "counters", "double_value"); + assertEquals(getMetadata(event), getMetadata(newPerfEvent)); + } + + @Test + public void checksPerformanceEventOnlyRequiredData() throws Exception { + Bundle bundle = new Bundle(); + bundle.putString("property ignored", "value will be ignored"); + PerformanceEvent event = new PerformanceEvent(UUID.randomUUID().toString(), bundle); + assertNotNull(event); + + Parcel parcel = Parcel.obtain(); + event.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel); + assertNotNull(newPerfEvent); + + assertEquals(getAttributes(event).size(), 0); + assertEquals(getCounters(event).size(), 0); + assertEquals(getAttributes(newPerfEvent).size(), 0); + assertEquals(getCounters(newPerfEvent).size(), 0); + assertEquals(getMetadata(event), getMetadata(newPerfEvent)); + } + + + private PerformanceEvent obtainPerformanceEvent() { + String styleStr = "mapbox://styles/mapbox/streets-v11"; + boolean testPerfEvent = true; + Double doubleValue = 40.5; + Long longValue = 40L; + Integer intValue = 40; + + List<Attribute<String>> attributes = new ArrayList<>(); + attributes.add( + new Attribute<>("style_id", styleStr)); + attributes.add( + new Attribute<>("test_perf_event", String.valueOf(testPerfEvent))); + + List<Attribute<? extends Number>> counters = new ArrayList(); + counters.add(new Attribute<>("long_value", longValue)); + counters.add(new Attribute<>("double_value", doubleValue)); + counters.add(new Attribute<>("int_value", intValue)); + + Gson gson = new Gson(); + + Bundle bundle = new Bundle(); + bundle.putString("attributes", gson.toJson(attributes)); + bundle.putString("counters", gson.toJson(counters)); + + JsonObject metaData = new JsonObject(); + metaData.addProperty("os", "android"); + metaData.addProperty("manufacturer", Build.MANUFACTURER); + metaData.addProperty("brand", Build.BRAND); + metaData.addProperty("device", Build.MODEL); + metaData.addProperty("version", Build.VERSION.RELEASE); + metaData.addProperty("abi", Build.CPU_ABI); + metaData.addProperty("country", Locale.getDefault().getISO3Country()); + metaData.addProperty("ram", getRam()); + metaData.addProperty("screenSize", getWindowSize()); + bundle.putString("metadata", metaData.toString()); + + return new PerformanceEvent(UUID.randomUUID().toString(), bundle); + } + + private void compare(PerformanceEvent event1, PerformanceEvent event2, String listFieldName, String name) + throws NoSuchFieldException, IllegalAccessException { + Object value1 = getValue(event1, listFieldName, name); + Object value2 = getValue(event2, listFieldName, name); + + if (value1 instanceof Double && value2 instanceof Double) { + assertEquals((Double)value1, (Double)value2, 0.00006); + } else { + assertEquals(value1, value2); + } + } + + private Object getPrivateFieldValue(Object object, String fieldName) + throws NoSuchFieldException, IllegalAccessException { + Field field = object.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(object); + } + + private Object getValue(PerformanceEvent event, String listFieldName, String name) + throws NoSuchFieldException, IllegalAccessException { + ArrayList list = (ArrayList)getPrivateFieldValue(event, listFieldName); + for (Object element : list) { + Object elementName = getPrivateFieldValue(element, "name"); + if (elementName != null && elementName.equals((String)name)) { + return getPrivateFieldValue(element, "value"); + } + } + return null; + } + + private JsonObject getMetadata(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (JsonObject)getPrivateFieldValue(event, "metadata"); + } + + private ArrayList getAttributes(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (ArrayList)getPrivateFieldValue(event, "attributes"); + } + + private ArrayList getCounters(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (ArrayList)getPrivateFieldValue(event, "counters"); + } + + private static String getRam() { + ActivityManager actManager = + (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + actManager.getMemoryInfo(memInfo); + return String.valueOf(memInfo.totalMem); + } + + private static String getWindowSize() { + WindowManager windowManager = + (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + int width = metrics.widthPixels; + int height = metrics.heightPixels; + + return "{" + width + "," + height + "}"; + } + + private class Attribute<T> { + private String name; + private T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java index 7f73d6a7f3..1bf5a87970 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.action; - import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; @@ -11,30 +10,31 @@ import android.view.View; import android.view.ViewGroup; import org.hamcrest.Matcher; +import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -public class OrientationChangeAction implements ViewAction { +public class OrientationAction implements ViewAction { private final int orientation; - private OrientationChangeAction(int orientation) { + private OrientationAction(int orientation) { this.orientation = orientation; } public static ViewAction orientationLandscape() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } public static ViewAction orientationPortrait() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } public static ViewAction orientationLandscapeReverse() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } public static ViewAction orientationPortraitReverse() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); } @Override @@ -61,6 +61,10 @@ public class OrientationChangeAction implements ViewAction { activity.setRequestedOrientation(orientation); } + public static void invoke(ViewAction action) { + onView(isRoot()).perform(action); + } + private Activity getActivity(Context context) { while (context instanceof ContextWrapper) { if (context instanceof Activity) { 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 index 5d98ccb7f8..e3741f3d42 100644 --- 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 @@ -3,10 +3,11 @@ 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.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; public final class WaitAction implements ViewAction { @@ -30,5 +31,9 @@ public final class WaitAction implements ViewAction { public void perform(UiController uiController, View view) { uiController.loopMainThreadForAtLeast(loopTime); } + + public static void invoke(long loopTime) { + onView(isRoot()).perform(new WaitAction(loopTime)); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java index ea69f8adae..c91afe9b60 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java @@ -1,116 +1,96 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.app.Activity; -import android.support.test.espresso.Espresso; -import android.support.test.espresso.IdlingRegistry; -import android.support.test.espresso.IdlingResource; -import android.support.test.espresso.IdlingResourceTimeoutException; -import android.support.test.espresso.ViewInteraction; +import android.support.annotation.CallSuper; +import android.support.annotation.UiThread; import android.support.test.rule.ActivityTestRule; - import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; -import com.mapbox.mapboxsdk.testapp.action.WaitAction; -import com.mapbox.mapboxsdk.testapp.utils.FinishLoadingStyleIdlingResource; - -import com.mapbox.mapboxsdk.testapp.utils.MapboxIdlingResource; -import junit.framework.Assert; - import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; - import timber.log.Timber; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; /** * Base class for all Activity test hooking into an existing Activity that will load style. */ public abstract class BaseTest { + private static final int WAIT_TIMEOUT = 30; //seconds + @Rule - public ActivityTestRule<Activity> rule = new ActivityTestRule<>(getActivityClass()); + public ActivityTestRule rule = new ActivityTestRule<>(getActivityClass()); @Rule - public TestName testNameRule = new TestName(); + public TestName testName = new TestName(); protected MapboxMap mapboxMap; - protected MapboxIdlingResource idlingResource; + protected MapView mapView; + private final CountDownLatch latch = new CountDownLatch(1); @Before + @CallSuper public void beforeTest() { - try { - Timber.e(String.format( - "%s - %s - %s", - getClass().getSimpleName(), - testNameRule.getMethodName(), - "@Before test: register idle resource" - )); - idlingResource = (MapboxIdlingResource) generateIdlingResource(); - IdlingRegistry.getInstance().register(idlingResource); - Espresso.onIdle(); - mapboxMap = idlingResource.getMapboxMap(); - } catch (IdlingResourceTimeoutException idlingResourceTimeoutException) { - throw new RuntimeException( - String.format( - "Could not start %s test for %s.", - testNameRule.getMethodName(), - getActivityClass().getSimpleName() - ) - ); - } + initialiseMap(); + holdTestRunnerForStyleLoad(); } - protected IdlingResource generateIdlingResource() { - return new FinishLoadingStyleIdlingResource(rule.getActivity()); + @After + @CallSuper + public void afterTest() { + // override to add logic + } + + @UiThread + @CallSuper + protected void initMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + mapboxMap.getStyle(style -> latch.countDown()); } protected void validateTestSetup() { if (!Mapbox.isConnected()) { Timber.e("Not connected to the internet while running test"); } - - checkViewIsDisplayed(R.id.mapView); - Assert.assertNotNull(mapboxMap); - } - - protected MapboxMap getMapboxMap() { - return mapboxMap; + assertNotNull("MapView isn't initialised", mapView); + assertNotNull("MapboxMap isn't initialised", mapboxMap); + assertNotNull("Style isn't initialised", mapboxMap.getStyle()); + assertTrue("Style isn't fully loaded", mapboxMap.getStyle().isFullyLoaded()); } protected abstract Class getActivityClass(); - protected void checkViewIsDisplayed(int id) { - onView(withId(id)).check(matches(isDisplayed())); - } - - protected void waitAction() { - waitAction(500); - } - - protected void waitAction(long waitTime) { - onView(withId(R.id.mapView)).perform(new WaitAction(waitTime)); - } - - protected ViewInteraction onMapView() { - return onView(withId(R.id.mapView)); + private void initialiseMap() { + try { + rule.runOnUiThread(() -> { + mapView = rule.getActivity().findViewById(R.id.mapView); + mapView.getMapAsync(this::initMap); + }); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } } - protected MapboxMapAction getMapboxMapAction(MapboxMapAction.OnInvokeActionListener onInvokeActionListener) { - return new MapboxMapAction(onInvokeActionListener, mapboxMap); - } + private void holdTestRunnerForStyleLoad() { + boolean interrupted; + try { + interrupted = latch.await(WAIT_TIMEOUT, TimeUnit.SECONDS); + } catch (InterruptedException ignore) { + interrupted = true; + } - @After - public void afterTest() { - Timber.e(String.format("%s - %s", testNameRule.getMethodName(), "@After test: unregister idle resource")); - IdlingRegistry.getInstance().unregister(idlingResource); + if (!interrupted) { + Timber.e("Timeout occurred for %s", testName.getMethodName()); + validateTestSetup(); + } } -} +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java index dfb4a46180..97a73ba1cb 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java @@ -1,24 +1,28 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.support.test.espresso.IdlingResource; +import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; -import com.mapbox.mapboxsdk.testapp.utils.LoadStyleIdlingResource; + /** * Base class for all tests using EspressoTestActivity as wrapper. * <p> - * Uses {@link LoadStyleIdlingResource} to load "assets/streets.json" as style. + * Loads "assets/streets.json" as style. * </p> */ public class EspressoTest extends BaseTest { @Override - protected IdlingResource generateIdlingResource() { - return new LoadStyleIdlingResource(rule.getActivity()); + protected final Class getActivityClass() { + return EspressoTestActivity.class; } + @UiThread @Override - protected final Class getActivityClass() { - return EspressoTestActivity.class; + protected void initMap(MapboxMap mapboxMap) { + mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json")); + super.initMap(mapboxMap); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java index 9fb823a377..559213af3d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.testapp.annotations; import android.app.Activity; +import android.support.test.annotation.UiThreadTest; import android.support.v4.content.res.ResourcesCompat; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; @@ -31,117 +32,107 @@ public class IconTest extends EspressoTest { @Before public void beforeTest() { super.beforeTest(); - iconMap = new IconManagerResolver(getMapboxMap()).getIconMap(); - } - - @Test - public void testEmpty() { - assertTrue(iconMap.isEmpty()); + iconMap = new IconManagerResolver(mapboxMap).getIconMap(); } @Test + @UiThreadTest public void testAddSameIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker(); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(1, iconMap.size()); - assertEquals(2, iconMap.get(defaultMarker), 0); - })); + Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker(); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(1, iconMap.size()); + assertEquals(2, iconMap.get(defaultMarker), 0); } @Test + @UiThreadTest public void testAddDifferentIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); - getMapboxMap().addMarker(new MarkerOptions().icon(icon).position(new LatLng())); - getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 2); - assertTrue(iconMap.containsKey(icon)); - assertTrue(iconMap.get(icon) == 1); - })); + Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); + mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 2); + assertTrue(iconMap.containsKey(icon)); + assertTrue(iconMap.get(icon) == 1); } @Test + @UiThreadTest public void testAddRemoveIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); - Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 2); - assertTrue(iconMap.containsKey(icon)); - assertTrue(iconMap.get(icon) == 1); - - mapboxMap.removeMarker(marker); - assertEquals(iconMap.size(), 1); - assertFalse(iconMap.containsKey(icon)); - })); + Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); + Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 2); + assertTrue(iconMap.containsKey(icon)); + assertTrue(iconMap.get(icon) == 1); + + mapboxMap.removeMarker(marker); + assertEquals(iconMap.size(), 1); + assertFalse(iconMap.containsKey(icon)); } @Test + @UiThreadTest public void testAddRemoveDefaultMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 1); + Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 1); - mapboxMap.removeMarker(marker); - assertEquals(iconMap.size(), 0); + mapboxMap.removeMarker(marker); + assertEquals(iconMap.size(), 0); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); - assertEquals(iconMap.size(), 1); - })); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); + assertEquals(iconMap.size(), 1); } @Test + @UiThreadTest public void testAddRemoveMany() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Activity activity = rule.getActivity(); - IconFactory iconFactory = IconFactory.getInstance(activity); - - // add 2 default icon markers - Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1))); - - // add 4 unique icon markers - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon)) - .position(new LatLng(3, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon)) - .position(new LatLng(4, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars, - ResourcesCompat.getColor(activity.getResources(), - R.color.blueAccent, activity.getTheme()))) - .position(new LatLng(5, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.ic_android)) - .position(new LatLng(6, 1)) - ); - - assertEquals("Amount of icons should match 5", 5, iconMap.size()); - assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0); - - mapboxMap.removeMarker(defaultMarkerOne); - - assertEquals("Amount of icons should match 5", 5, iconMap.size()); - assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0); - - mapboxMap.removeMarker(defaultMarkerTwo); - - assertEquals("Amount of icons should match 4", 4, iconMap.size()); - assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker())); - - mapboxMap.clear(); - assertEquals("Amount of icons should match 0", 0, iconMap.size()); - })); + Activity activity = rule.getActivity(); + IconFactory iconFactory = IconFactory.getInstance(activity); + + // add 2 default icon markers + Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1))); + + // add 4 unique icon markers + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon)) + .position(new LatLng(3, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon)) + .position(new LatLng(4, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars, + ResourcesCompat.getColor(activity.getResources(), + R.color.blueAccent, activity.getTheme()))) + .position(new LatLng(5, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.ic_android)) + .position(new LatLng(6, 1)) + ); + + assertEquals("Amount of icons should match 5", 5, iconMap.size()); + assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0); + + mapboxMap.removeMarker(defaultMarkerOne); + + assertEquals("Amount of icons should match 5", 5, iconMap.size()); + assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0); + + mapboxMap.removeMarker(defaultMarkerTwo); + + assertEquals("Amount of icons should match 4", 4, iconMap.size()); + assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker())); + + mapboxMap.clear(); + assertEquals("Amount of icons should match 0", 0, iconMap.size()); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java index eb38bddf84..4365ea95ff 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.testapp.camera; import android.support.annotation.NonNull; +import android.support.test.annotation.UiThreadTest; import com.mapbox.geojson.Point; import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.camera.CameraPosition; @@ -18,123 +19,117 @@ import static org.junit.Assert.assertEquals; public class CameraForTest extends BaseTest { @Test + @UiThreadTest public void testGetCameraForLatLngBounds() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10)); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Bearing should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10)); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Bearing should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsPadding() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsBearing() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsTilt() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), 0, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), 0, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsAll() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometry() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition)); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Bearing should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition)); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Bearing should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); } @NonNull @@ -154,113 +149,108 @@ public class CameraForTest extends BaseTest { } @Test + @UiThreadTest public void testGetCameraForGeometryPadding() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryBearing() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryTilt() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryAll() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}, 45, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}, 45, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryDeprecatedApi() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry( - Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}, - 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry( + Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}, + 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt index 418191e91a..2731b20db7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt @@ -10,6 +10,7 @@ import android.support.test.runner.AndroidJUnit4 import com.mapbox.mapboxsdk.testapp.R import com.mapbox.mapboxsdk.testapp.action.WaitAction import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapInDialogActivity +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -25,9 +26,10 @@ class MapDialogFragmentTest { var activityRule: ActivityTestRule<MapInDialogActivity> = ActivityTestRule(MapInDialogActivity::class.java) @Test + @Ignore fun openCloseDialog() { onView(withId(R.id.button_open_dialog)).perform(click()) - onView(withId(R.id.mapView)).perform(WaitAction(2500)) + Thread.sleep(2500) Espresso.pressBack() } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java index c34e76a6e5..f30b3aa8cf 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.testapp.geometry; +import android.support.test.annotation.UiThreadTest; import com.google.gson.JsonArray; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; @@ -13,11 +14,13 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.style.sources.GeometryTileProvider; +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils; - import org.junit.Test; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static com.mapbox.geojson.Feature.fromGeometry; import static com.mapbox.geojson.FeatureCollection.fromFeatures; import static com.mapbox.geojson.GeometryCollection.fromGeometries; @@ -35,101 +38,94 @@ public class GeoJsonConversionTest extends EspressoTest { // Regression test for #12343 @Test + @UiThreadTest public void testEmptyFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testPointFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiPointFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } - @Test + @UiThreadTest public void testPolygonFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiPolygonFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList())))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList())))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testLineStringFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiLineStringFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList())))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList())))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } + @Test public void testNegativeNumberPropertyConversion() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { + onView(isRoot()).perform(new MapboxMapAction((uiController, mapboxMap) -> { LatLng latLng = new LatLng(); Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())); @@ -148,10 +144,10 @@ public class GeoJsonConversionTest extends EspressoTest { ); mapboxMap.getStyle().addLayer(layer); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng)).isEmpty()); - })); + }, mapboxMap)); } class CustomProvider implements GeometryTileProvider { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt index 84af279bd0..ac73b028f3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt @@ -18,14 +18,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class StyleLoadTest : EspressoTest() { - private lateinit var mapView: MapView - - @Before - override fun beforeTest() { - super.beforeTest() - mapView = (rule.activity as EspressoTestActivity).mapView - } - @Test fun updateSourceAfterStyleLoad() { validateTestSetup() diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java index 0fadd33325..ca5c9adc1f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets; import android.app.Instrumentation; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.intent.Intents; @@ -31,12 +32,14 @@ import static android.support.test.espresso.intent.Intents.intended; import static android.support.test.espresso.intent.Intents.intending; import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction; import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData; +import static android.support.test.espresso.matcher.RootMatchers.isDialog; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anything; import static org.hamcrest.core.IsNot.not; +import static org.junit.Assume.assumeTrue; public class AttributionTest extends EspressoTest { @@ -126,15 +129,20 @@ public class AttributionTest extends EspressoTest { @Test public void testTelemetryDialog() { + assumeTrue( + "Can only run on API Level 23 or newer because of instability", + Build.VERSION.SDK_INT >= 23 + ); + validateTestSetup(); // click on View to open dialog onView(withId(R.id.attributionView)).perform(click()); - onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed())); + onView(withText(R.string.mapbox_attributionsDialogTitle)).inRoot(isDialog()).check(matches(isDisplayed())); // click on item to open second dialog - onView(withText(R.string.mapbox_telemetrySettings)).perform(click()); - onView(withText(R.string.mapbox_attributionTelemetryTitle)).check(matches(isDisplayed())); + onView(withText(R.string.mapbox_telemetrySettings)).inRoot(isDialog()).perform(click()); + onView(withText(R.string.mapbox_attributionTelemetryTitle)).inRoot(isDialog()).check(matches(isDisplayed())); } @After @@ -206,4 +214,4 @@ public class AttributionTest extends EspressoTest { interface InvokeViewAction { void onViewAction(UiController uiController, View view); } -} +}
\ No newline at end of file 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 1cdf1423a3..8b62ee7612 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 @@ -4,6 +4,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.action.WaitAction; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestConstants; import org.junit.Ignore; @@ -55,7 +56,7 @@ public class CompassViewTest extends EspressoTest { .build() ))); onView(withId(R.id.compassView)).perform(click()); - waitAction(); + WaitAction.invoke(500); 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/offline/OfflineManagerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt index 144d67feee..8e5f3f7c5f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt @@ -1,59 +1,43 @@ package com.mapbox.mapboxsdk.testapp.offline import android.content.Context -import android.support.test.espresso.Espresso -import android.support.test.espresso.IdlingRegistry -import android.support.test.espresso.UiController -import android.support.test.espresso.idling.CountingIdlingResource +import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 -import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.offline.OfflineRegion import com.mapbox.mapboxsdk.storage.FileSource -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest +import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity import com.mapbox.mapboxsdk.testapp.utils.FileUtils +import org.junit.FixMethodOrder +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.junit.runners.MethodSorters import java.io.IOException +import java.util.concurrent.CountDownLatch +@FixMethodOrder(MethodSorters.NAME_ASCENDING) @RunWith(AndroidJUnit4::class) -class OfflineManagerTest : EspressoTest() { +class OfflineManagerTest { companion object { private const val TEST_DB_FILE_NAME = "offline_test.db" + private lateinit var mergedRegion: OfflineRegion } - private val context: Context by lazy { rule.activity } - - private lateinit var offlineIdlingResource: CountingIdlingResource - - override fun beforeTest() { - super.beforeTest() - offlineIdlingResource = CountingIdlingResource("idling_resource") - IdlingRegistry.getInstance().register(offlineIdlingResource) - } + @Rule + @JvmField + var rule = ActivityTestRule(FeatureOverviewActivity::class.java) - @Test - fun offlineMergeListDeleteTest() { - validateTestSetup() + private val context: Context by lazy { rule.activity } - invoke(mapboxMap) { _: UiController, _: MapboxMap -> - offlineIdlingResource.increment() + @Test(timeout = 30_000) + fun a_copyFileFromAssets() { + val latch = CountDownLatch(1) + rule.runOnUiThread { FileUtils.CopyFileFromAssetsTask(rule.activity, object : FileUtils.OnFileCopiedFromAssetsListener { override fun onFileCopiedFromAssets() { - OfflineManager.getInstance(context).mergeOfflineRegions( - FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME, - object : OfflineManager.MergeOfflineRegionsCallback { - override fun onMerge(offlineRegions: Array<out OfflineRegion>?) { - assert(offlineRegions?.size == 1) - offlineIdlingResource.decrement() - } - - override fun onError(error: String?) { - throw RuntimeException("Unable to merge external offline database. $error") - } - }) + latch.countDown() } override fun onError() { @@ -61,43 +45,62 @@ class OfflineManagerTest : EspressoTest() { } }).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity)) } + latch.await() + } + + @Test(timeout = 30_000) + fun b_mergeRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { + OfflineManager.getInstance(context).mergeOfflineRegions( + FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME, + object : OfflineManager.MergeOfflineRegionsCallback { + override fun onMerge(offlineRegions: Array<out OfflineRegion>?) { + assert(offlineRegions?.size == 1) + latch.countDown() + } + + override fun onError(error: String?) { + throw RuntimeException("Unable to merge external offline database. $error") + } + }) + } + latch.await() + } - invoke(mapboxMap) { _: UiController, _: MapboxMap -> - offlineIdlingResource.increment() + @Test(timeout = 30_000) + fun c_listRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback { override fun onList(offlineRegions: Array<out OfflineRegion>?) { assert(offlineRegions?.size == 1) - if (offlineRegions != null) { - for (region in offlineRegions) { - offlineIdlingResource.increment() - region.delete(object : OfflineRegion.OfflineRegionDeleteCallback { - override fun onDelete() { - offlineIdlingResource.decrement() - } - - override fun onError(error: String?) { - throw RuntimeException("Unable to delete region with ID: ${region.id}. $error") - } - }) - } - } else { - throw RuntimeException("Unable to find merged region.") - } - offlineIdlingResource.decrement() + mergedRegion = offlineRegions!![0] + latch.countDown() } override fun onError(error: String?) { - throw RuntimeException("Unable to obtain offline regions list. $error") + throw RuntimeException("Unable to merge external offline database. $error") } }) } - - // waiting for offline idling resource - Espresso.onIdle() + latch.await() } - override fun afterTest() { - super.afterTest() - IdlingRegistry.getInstance().unregister(offlineIdlingResource) + @Test(timeout = 30_000) + fun d_deleteRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { + mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback { + override fun onDelete() { + latch.countDown() + } + + override fun onError(error: String?) { + throw RuntimeException("Unable to delete region") + } + }) + } + latch.await() } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index eb458ab8f5..a6238ebf14 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -6,8 +6,9 @@ import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_POOL_LIMIT import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_PREFIX import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape -import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait +import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationLandscape +import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationPortrait +import com.mapbox.mapboxsdk.testapp.action.WaitAction import com.mapbox.mapboxsdk.testapp.activity.BaseTest import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LAYER @@ -25,11 +26,11 @@ class CustomGeometrySourceTest : BaseTest() { @Ignore fun sourceNotLeakingThreadsTest() { validateTestSetup() - waitAction(4000) + WaitAction.invoke(4000) onView(isRoot()).perform(orientationLandscape()) - waitAction(2000) + WaitAction.invoke(2000) onView(isRoot()).perform(orientationPortrait()) - waitAction(2000) + WaitAction.invoke(2000) Assert.assertFalse("Threads should be shutdown when the source is destroyed.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(THREAD_PREFIX) @@ -42,9 +43,9 @@ class CustomGeometrySourceTest : BaseTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> mapboxMap.style!!.removeLayer(ID_GRID_LAYER) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.removeSource(ID_GRID_SOURCE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) Assert.assertTrue("There should be no threads running when the source is removed.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) @@ -58,12 +59,12 @@ class CustomGeometrySourceTest : BaseTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.removeSource(ID_GRID_SOURCE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source) mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) Assert.assertTrue("Threads should be restarted when the source is re-added to the map.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java index 75dcbf1209..ff3b2a9d6d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java @@ -252,7 +252,7 @@ public class ExpressionTest extends EspressoTest { ) )); mapboxMap.getStyle().addLayer(layer); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -262,7 +262,7 @@ public class ExpressionTest extends EspressoTest { literal(ColorUtils.colorToRgbaString(Color.RED)) ) )); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -272,7 +272,7 @@ public class ExpressionTest extends EspressoTest { literal(ColorUtils.colorToRgbaString(Color.RED)) ) )); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); }); @@ -292,7 +292,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("test") ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -315,7 +315,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("test", formatFontScale(1.75)) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -341,7 +341,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -371,7 +371,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -402,7 +402,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -436,7 +436,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("\ntest2", formatFontScale(2), formatTextColor(Color.BLUE)) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -472,7 +472,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -504,7 +504,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("\ntest2", formatFontScale(2)) ); layer.setProperties(textField(expression), textColor("rgba(128, 0, 0, 1)")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -524,7 +524,7 @@ public class ExpressionTest extends EspressoTest { mapboxMap.getStyle().addLayer(layer); layer.setProperties(textField("test")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -550,7 +550,7 @@ public class ExpressionTest extends EspressoTest { new FormattedSection("test", null, null, "rgba(0, 255, 0, 1)") ); layer.setProperties(textField(formatted), textColor("rgba(128, 0, 0, 1)")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java index 92d060fee4..99e0ae4016 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java @@ -94,7 +94,7 @@ public class GeoJsonSourceTests extends EspressoTest { } source.setGeoJson(Point.fromLngLat(20, 55)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertEquals(1, mapboxMap.queryRenderedFeatures( mapboxMap.getProjection().toScreenLocation( new LatLng(55, 20)), "layer").size()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java deleted file mode 100644 index 0e4c8f3f2e..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.style; - -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.support.test.runner.AndroidJUnit4; - -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; - -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * CRUD tests around Image - */ -@RunWith(AndroidJUnit4.class) -public class ImageTest extends EspressoTest { - - private static final String IMAGE_ID = "test.image"; - - @Test - public void testAddGetImage() { - validateTestSetup(); - MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { - Drawable drawable = rule.getActivity().getResources().getDrawable(R.drawable.ic_launcher_round); - assertTrue(drawable instanceof BitmapDrawable); - - Bitmap bitmapSet = ((BitmapDrawable) drawable).getBitmap(); - mapboxMap.getStyle().addImage(IMAGE_ID, bitmapSet); - - // adding an image requires converting the image with an asynctask - uiController.loopMainThreadForAtLeast(200); - - Bitmap bitmapGet = mapboxMap.getStyle().getImage(IMAGE_ID); - assertTrue(bitmapGet.sameAs(bitmapSet)); - - mapboxMap.getStyle().removeImage(IMAGE_ID); - assertNull(mapboxMap.getStyle().getImage(IMAGE_ID)); - }); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt new file mode 100644 index 0000000000..9cef677e7c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt @@ -0,0 +1,75 @@ +package com.mapbox.mapboxsdk.testapp.style + +import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.R +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction +import com.mapbox.mapboxsdk.testapp.activity.EspressoTest +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +/** + * CRUD tests around Image + */ +@RunWith(AndroidJUnit4::class) +class ImageTest : EspressoTest() { + + companion object { + private const val IMAGE_ID = "test.image" + } + + @Test + fun testAddGetImage() { + validateTestSetup() + MapboxMapAction.invoke(mapboxMap) { uiController, mapboxMap -> + val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round) + assertTrue(drawable is BitmapDrawable) + + val bitmapSet = (drawable as BitmapDrawable).bitmap + mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet) + + // adding an image requires converting the image with an asynctask + uiController.loopMainThreadForAtLeast(200) + + val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID) + assertTrue(bitmapGet!!.similarTo(bitmapSet)) + + mapboxMap.style!!.removeImage(IMAGE_ID) + assertNull(mapboxMap.style!!.getImage(IMAGE_ID)) + } + } +} + +/** + * Alternative implementation of Bitmap.sameAs #14060 + */ +fun Bitmap.similarTo(other: Bitmap): Boolean { + if (invalidConfig(other)) { + return false + } + + // Allocate arrays + val argb = IntArray(width * height) + val argbOther = IntArray(other.width * other.height) + getPixels(argb, 0, width, 0, 0, width, height) + other.getPixels(argbOther, 0, width, 0, 0, width, height) + + // Alpha channel special check + if (config == Bitmap.Config.ALPHA_8) { + // in this case we have to manually compare the alpha channel as the rest is garbage. + val length = width * height + for (i in 0 until length) { + if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) { + return false + } + } + return true + } + return Arrays.equals(argb, argbOther) +} + +fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height
\ No newline at end of file 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 ed39f36e32..a4a34e752e 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 @@ -2,12 +2,10 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; import android.graphics.PointF; -import android.support.test.espresso.Espresso; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.runner.AndroidJUnit4; import android.view.View; - import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.FillLayer; @@ -22,20 +20,16 @@ import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.style.sources.VectorSource; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; - import junit.framework.Assert; - import org.hamcrest.Matcher; -import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; +import timber.log.Timber; import java.net.MalformedURLException; import java.net.URL; import java.util.List; -import timber.log.Timber; - import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; @@ -366,11 +360,6 @@ public class RuntimeStyleTests extends EspressoTest { } } - @After - public void unregisterIntentServiceIdlingResource() { - Espresso.unregisterIdlingResources(idlingResource); - } - public abstract class BaseViewAction implements ViewAction { @Override 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 149064d684..ae2c6d98f6 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 @@ -559,7 +559,7 @@ public class SymbolLayerTest extends BaseLayerTest { assertNull(layer.getTextJustify().getValue()); // Set and Get - String propertyValue = TEXT_JUSTIFY_LEFT; + String propertyValue = TEXT_JUSTIFY_AUTO; layer.setProperties(textJustify(propertyValue)); assertEquals(layer.getTextJustify().getValue(), propertyValue); } @@ -579,6 +579,32 @@ public class SymbolLayerTest extends BaseLayerTest { @Test @UiThreadTest + public void testTextRadialOffsetAsConstant() { + Timber.i("text-radial-offset"); + assertNotNull(layer); + assertNull(layer.getTextRadialOffset().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(textRadialOffset(propertyValue)); + assertEquals(layer.getTextRadialOffset().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testTextVariableAnchorAsConstant() { + Timber.i("text-variable-anchor"); + assertNotNull(layer); + assertNull(layer.getTextVariableAnchor().getValue()); + + // Set and Get + String[] propertyValue = new String[0]; + layer.setProperties(textVariableAnchor(propertyValue)); + assertEquals(layer.getTextVariableAnchor().getValue(), propertyValue); + } + + @Test + @UiThreadTest public void testTextAnchorAsConstant() { Timber.i("text-anchor"); assertNotNull(layer); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java deleted file mode 100644 index 323d2c0f15..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.WorkerThread; -import com.mapbox.mapboxsdk.maps.MapboxMap; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class FinishLoadingStyleIdlingResource extends MapboxIdlingResource { - - @WorkerThread - public FinishLoadingStyleIdlingResource(final Activity activity) { - new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity)); - } - - @Override - public void initMap(MapboxMap mapboxMap) { - super.initMap(mapboxMap); - mapboxMap.getStyle(style -> { - assertNotNull(style); - assertTrue(style.isFullyLoaded()); - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - } - - @Override - public boolean isIdleNow() { - return getMapboxMap() != null && getMapboxMap().getStyle() != null; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java deleted file mode 100644 index 5dead21fbb..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.UiThread; -import android.support.annotation.WorkerThread; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Style; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class LoadStyleIdlingResource extends MapboxIdlingResource { - - private Style style; - - @WorkerThread - public LoadStyleIdlingResource(final Activity activity) { - new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity)); - } - - @UiThread - public void initMap(MapboxMap mapboxMap) { - super.initMap(mapboxMap); - mapboxMap.setStyle("asset://streets.json", style -> { - assertNotNull(style); - assertTrue(style.isFullyLoaded()); - this.style = style; - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - } - - @Override - public boolean isIdleNow() { - return style != null; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java deleted file mode 100644 index a05221d618..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.support.annotation.UiThread; -import android.support.test.espresso.IdlingResource; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; - -public abstract class MapboxIdlingResource implements IdlingResource { - - private MapView mapView; - private MapboxMap mapboxMap; - IdlingResource.ResourceCallback resourceCallback; - - @UiThread - void inflateMap(Activity activity) { - mapView = activity.findViewById(R.id.mapView); - if (mapView != null) { - mapView.getMapAsync(this::initMap); - } - } - - @UiThread - protected void initMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public String getName() { - return getClass().getSimpleName(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - public MapboxMap getMapboxMap() { - return mapboxMap; - } - - public MapView getMapView() { - return mapView; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java deleted file mode 100644 index 7696447289..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.WorkerThread; -import android.support.test.espresso.IdlingResource; - -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.testapp.R; - -public class OnMapReadyIdlingResource implements IdlingResource { - - private boolean styleLoaded; - private MapboxMap mapboxMap; - private IdlingResource.ResourceCallback resourceCallback; - - @WorkerThread - public OnMapReadyIdlingResource(final Activity activity) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> { - MapView mapView = activity.findViewById(R.id.mapView); - if (mapView != null) { - mapView.addOnDidFinishLoadingStyleListener(() -> { - styleLoaded = true; - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - mapView.getMapAsync(this::initMap); - } - }); - } - - private void initMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json")); - } - - @Override - public String getName() { - return getClass().getSimpleName(); - } - - @Override - public boolean isIdleNow() { - return styleLoaded; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - public MapboxMap getMapboxMap() { - return mapboxMap; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 2fa26f822a..017fe3ddca 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -173,10 +173,11 @@ <activity android:name=".activity.fragment.FragmentBackStackActivity" android:description="@string/description_map_fragment_backstack" - android:label="@string/activity_map_fragment_backstack"> + android:label="@string/activity_map_fragment_backstack" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> @@ -399,7 +400,7 @@ android:label="@string/activity_viewpager"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> @@ -407,7 +408,8 @@ <activity android:name=".activity.maplayout.SimpleMapActivity" android:description="@string/description_simple_map" - android:label="@string/activity_simple_map"> + android:label="@string/activity_simple_map" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" android:value="@string/category_basic" /> @@ -720,7 +722,8 @@ <activity android:name=".activity.textureview.TextureViewDebugModeActivity" android:description="@string/description_textureview_debug" - android:label="@string/activity_textureview_debug"> + android:label="@string/activity_textureview_debug" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" android:value="@string/category_basic" /> @@ -895,27 +898,49 @@ android:value=".activity.FeatureOverviewActivity" /> </activity> <activity - android:name=".activity.maplayout.RecyclerViewActivity" - android:description="@string/description_recyclerview" - android:label="@string/activity_recyclerview"> + android:name=".activity.maplayout.TextureRecyclerViewActivity" + android:description="@string/description_recyclerview_textureview" + android:label="@string/activity_recyclerview_textureview"> <meta-data android:name="@string/category" - android:value="@string/category_maplayout" /> + android:value="@string/category_integration" /> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + </activity> + <activity + android:name=".activity.maplayout.GLSurfaceRecyclerViewActivity" + android:description="@string/description_recyclerview_glsurfaceview" + android:label="@string/activity_recyclerview_glsurfaceview"> + <meta-data + android:name="@string/category" + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> </activity> <activity android:name=".activity.fragment.NestedViewPagerActivity" - android:description="@string/description_recyclerview" + android:description="@string/description_nested_viewpager" android:label="@string/activity_nested_viewpager"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> </activity> + <activity + android:name=".activity.telemetry.PerformanceMeasurementActivity" + android:description="@string/description_performance_measurement" + android:label="@string/activity_performance_measurement"> + <meta-data + android:name="@string/category" + android:value="@string/category_telemetry" /> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + </activity> <!-- For Instrumentation tests --> <activity android:name=".activity.style.RuntimeStyleTimingTestActivity" @@ -924,6 +949,9 @@ android:name=".activity.espresso.EspressoTestActivity" android:screenOrientation="portrait" /> <activity + android:name=".activity.espresso.PixelTestActivity" + android:screenOrientation="portrait" /> + <activity android:name=".activity.espresso.DeviceIndependentTestActivity" android:screenOrientation="portrait" /> <activity diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java index 9ade97f91e..d5cff301db 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java @@ -40,7 +40,7 @@ public class MapboxApplication extends Application { initializeMapbox(); } - private boolean initializeLeakCanary() { + protected boolean initializeLeakCanary() { if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java index f4639b0f1a..ed5364655e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java @@ -267,7 +267,18 @@ public class GestureDetectorActivity extends AppCompatActivity { if (enabled) { focalPointLatLng = new LatLng(51.50325, -0.12968); marker = mapboxMap.addMarker(new MarkerOptions().position(focalPointLatLng)); - mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16)); + mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16), + new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + recalculateFocalPoint(); + } + + @Override + public void onFinish() { + recalculateFocalPoint(); + } + }); } else { if (marker != null) { mapboxMap.removeMarker(marker); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt new file mode 100644 index 0000000000..b69d1ee5ed --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.testapp.activity.espresso + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R + +/** + * Test activity used for instrumentation tests that require a specific device size. + */ +class PixelTestActivity : AppCompatActivity(), OnMapReadyCallback { + + lateinit var mapView: MapView + lateinit var mapboxMap: MapboxMap + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_pixel_test) + mapView = findViewById(R.id.mapView) + mapView.onCreate(savedInstanceState) + mapView.getMapAsync(this) + } + + override fun onMapReady(map: MapboxMap) { + mapboxMap = map + mapboxMap.setStyle(Style.MAPBOX_STREETS) + } + + public override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + public override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + mapView.onDestroy() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } +} 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 472b9b7d57..c7f530b123 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 @@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.maps.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; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.testapp.R; /** @@ -24,6 +23,7 @@ import com.mapbox.mapboxsdk.testapp.R; public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener { + private static final String TAG = "com.mapbox.map"; private MapboxMap mapboxMap; private MapView mapView; private boolean initialCameraAnimation = true; @@ -32,14 +32,18 @@ public class MapFragmentActivity extends AppCompatActivity implements MapFragmen protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); + + MapFragment mapFragment; if (savedInstanceState == null) { - MapFragment mapFragment = MapFragment.newInstance(createFragmentOptions()); + mapFragment = MapFragment.newInstance(createFragmentOptions()); getFragmentManager() .beginTransaction() - .add(R.id.fragment_container, mapFragment, "com.mapbox.map") + .add(R.id.fragment_container, mapFragment, TAG) .commit(); - mapFragment.getMapAsync(this); + } else { + mapFragment = (MapFragment) getFragmentManager().findFragmentByTag(TAG); } + mapFragment.getMapAsync(this); } private MapboxMapOptions createFragmentOptions() { 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 4baf40d51b..7fd84bcd25 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 @@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.maps.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; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.SupportMapFragment; import com.mapbox.mapboxsdk.testapp.R; @@ -25,6 +24,7 @@ import com.mapbox.mapboxsdk.testapp.R; public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener { + private static final String TAG = "com.mapbox.map"; private MapboxMap mapboxMap; private MapView mapView; private boolean initialCameraAnimation = true; @@ -33,14 +33,18 @@ public class SupportMapFragmentActivity extends AppCompatActivity implements Map protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); + SupportMapFragment mapFragment; if (savedInstanceState == null) { - SupportMapFragment mapFragment = SupportMapFragment.newInstance(createFragmentOptions()); + mapFragment = SupportMapFragment.newInstance(createFragmentOptions()); getSupportFragmentManager() .beginTransaction() - .add(R.id.fragment_container, mapFragment, "com.mapbox.map") + .add(R.id.fragment_container, mapFragment, TAG) .commit(); - mapFragment.getMapAsync(this); + } else { + mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag(TAG); } + mapFragment.getMapAsync(this); + } private MapboxMapOptions createFragmentOptions() { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java deleted file mode 100644 index c494842b14..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.fragment; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; - -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMapOptions; -import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.maps.SupportMapFragment; -import com.mapbox.mapboxsdk.testapp.R; - -/** - * Test activity showcasing using the Android SDK ViewPager API to show MapFragments. - */ -public class ViewPagerActivity extends AppCompatActivity { - - private ViewPager viewPager; - private MapFragmentAdapter adapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_viewpager); - - viewPager = (ViewPager) findViewById(R.id.viewpager); - if (viewPager != null) { - adapter = new MapFragmentAdapter(getSupportFragmentManager()); - viewPager.setAdapter(adapter); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - - int currentPosition = viewPager.getCurrentItem(); - SupportMapFragment mapFragment; - - if (Math.abs(0 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 0); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.MAPBOX_STREETS); - }); - } - - if (Math.abs(1 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 1); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.DARK); - }); - } - - if (Math.abs(2 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 2); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.SATELLITE); - }); - } - } - - static class MapFragmentAdapter extends FragmentStatePagerAdapter { - - private static int NUM_ITEMS = 3; - - MapFragmentAdapter(FragmentManager fragmentManager) { - super(fragmentManager); - } - - @Override - public int getCount() { - return NUM_ITEMS; - } - - @Override - public Fragment getItem(int position) { - SupportMapFragment fragment = null; - MapboxMapOptions options = new MapboxMapOptions(); - options.textureMode(true); - - switch (position) { - case 0: - options.camera(new CameraPosition.Builder().target(new LatLng(34.920526, 102.634774)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.MAPBOX_STREETS); - }); - break; - case 1: - options.camera(new CameraPosition.Builder().target(new LatLng(62.326440, 92.764913)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.DARK); - }); - break; - case 2: - options.camera(new CameraPosition.Builder().target(new LatLng(-25.007786, 133.623852)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.SATELLITE); - }); - break; - } - return fragment; - } - - @Override - public CharSequence getPageTitle(int position) { - return "Page " + position; - } - } -} - diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt new file mode 100644 index 0000000000..77e2e1370d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt @@ -0,0 +1,109 @@ +package com.mapbox.mapboxsdk.testapp.activity.fragment + +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentStatePagerAdapter +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.maps.MapboxMapOptions +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.maps.SupportMapFragment +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_viewpager.* + +/** + * Test activity showcasing using the Android SDK ViewPager API to show MapFragments. + */ +class ViewPagerActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_viewpager) + viewPager.adapter = MapFragmentAdapter(supportFragmentManager) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + + val currentPosition = viewPager.currentItem + var mapFragment: SupportMapFragment + + if (Math.abs(0 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 0) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + } + + if (Math.abs(1 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 1) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) } + } + + if (Math.abs(2 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 2) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + + if (Math.abs(3 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 3) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + + if (Math.abs(4 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 4) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + } + + internal class MapFragmentAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) { + + override fun getCount(): Int { + return NUM_ITEMS + } + + override fun getItem(position: Int): Fragment? { + var fragment: SupportMapFragment? = null + val options = MapboxMapOptions() + options.textureMode(true) + + when (position) { + 0 -> { + options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + } + 1 -> { + options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) } + } + 2 -> { + options.camera(CameraPosition.Builder().target(LatLng(-25.007786, 133.623852)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + 3 -> { + options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.LIGHT) } + } + 4 -> { + options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.TRAFFIC_NIGHT) } + } + } + return fragment + } + + override fun getPageTitle(position: Int): CharSequence? { + return "Page $position" + } + + companion object { + + private val NUM_ITEMS = 5 + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java deleted file mode 100644 index c1697ab960..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.imagegenerator; - -import android.graphics.Bitmap; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.widget.ImageView; -import android.widget.Toast; - -import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.testapp.R; - -import java.util.Locale; - -import timber.log.Timber; - -/** - * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map. - */ -public class SnapshotActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnClickListener { - - private MapView mapView; - private MapboxMap mapboxMap; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_snapshot); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(this); - } - - @Override - public void onMapReady(@NonNull MapboxMap map) { - mapboxMap = map; - mapboxMap.setStyle(new Style.Builder().fromUrl(Style.OUTDOORS)); - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - if (fab != null) { - fab.setColorFilter(ContextCompat.getColor(SnapshotActivity.this, R.color.primary)); - fab.setOnClickListener(this); - } - } - - @Override - public void onClick(View view) { - final long startTime = System.nanoTime(); - mapboxMap.snapshot(snapshot -> { - long endTime = System.nanoTime(); - long duration = (long) ((endTime - startTime) / 1e6); - ImageView snapshotView = (ImageView) findViewById(R.id.imageView); - snapshotView.setImageBitmap(snapshot); - Toast.makeText( - SnapshotActivity.this, - String.format(Locale.getDefault(), "Snapshot taken in %d ms", duration), - Toast.LENGTH_LONG).show(); - }); - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapboxMap.snapshot(new MapboxMap.SnapshotReadyCallback() { - @Override - public void onSnapshotReady(Bitmap snapshot) { - Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358"); - } - }); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt new file mode 100644 index 0000000000..51b1c08ba5 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt @@ -0,0 +1,80 @@ +package com.mapbox.mapboxsdk.testapp.activity.imagegenerator + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_snapshot.* +import timber.log.Timber + +/** + * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map. + */ +class SnapshotActivity : AppCompatActivity(), OnMapReadyCallback { + + private lateinit var mapboxMap: MapboxMap + + private val idleListener = object : MapView.OnDidBecomeIdleListener { + override fun onDidBecomeIdle() { + mapView.removeOnDidBecomeIdleListener(this) + mapboxMap.snapshot { snapshot -> + imageView.setImageBitmap(snapshot) + mapView.addOnDidBecomeIdleListener(this) + } + } + } + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_snapshot) + mapView.onCreate(savedInstanceState) + mapView.getMapAsync(this) + } + + override fun onMapReady(map: MapboxMap) { + mapboxMap = map + mapboxMap.setStyle(Style.Builder().fromUrl(Style.OUTDOORS)) { mapView.addOnDidBecomeIdleListener(idleListener) } + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapboxMap.snapshot { + Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358") + } + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + public override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + public override fun onDestroy() { + super.onDestroy() + mapView.removeOnDidBecomeIdleListener(idleListener) + mapView.onDestroy() + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt new file mode 100644 index 0000000000..5acf356696 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt @@ -0,0 +1,155 @@ +package com.mapbox.mapboxsdk.testapp.activity.maplayout + +import android.annotation.SuppressLint +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.TextView +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_recyclerview.* + +/** + * TestActivity showcasing how to integrate a GLSurfaceView MapView in a RecyclerView. + * <p> + * It requires calling the correct lifecycle methods when detaching and attaching the View to + * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow. + * </p> + */ +@SuppressLint("ClickableViewAccessibility") +open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_recyclerview) + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this), savedInstanceState) + } + + override fun onSaveInstanceState(outState: Bundle?) { + super.onSaveInstanceState(outState) + // to save state, we need to call MapView#onSaveInstanceState + (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState) + } + + override fun onLowMemory() { + super.onLowMemory() + // to release memory, we need to call MapView#onLowMemory + (recyclerView.adapter as ItemAdapter).onLowMemory() + } + + override fun onDestroy() { + super.onDestroy() + // to perform cleanup, we need to call MapView#onDestroy + (recyclerView.adapter as ItemAdapter).onDestroy() + } + + open fun getMapItemLayoutId(): Int { + return R.layout.item_map_gl + } + + class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { + + private val items = listOf( + "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", + "nineteen", "twenty", "twenty-one" + ) + + private var mapHolder: MapHolder? = null + + companion object { + const val TYPE_MAP = 0 + const val TYPE_TEXT = 1 + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return if (viewType == TYPE_MAP) { + val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView + mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + mapHolder = MapHolder(mapView, savedInstanceState) + return mapHolder as MapHolder + } else { + TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView) + } + } + + override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { + super.onViewAttachedToWindow(holder) + if (holder is MapHolder) { + val mapView = holder.mapView + mapView.onStart() + mapView.onResume() + } + } + + override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { + super.onViewDetachedFromWindow(holder) + if (holder is MapHolder) { + val mapView = holder.mapView + mapView.onPause() + mapView.onStop() + } + } + + override fun getItemCount(): Int { + return items.count() + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder.itemViewType == TYPE_TEXT) { + val textHolder = holder as TextHolder + textHolder.bind(items[position] as String) + } + } + + override fun getItemViewType(position: Int): Int { + return if (items[position] is MapItem) { + TYPE_MAP + } else { + TYPE_TEXT + } + } + + fun onSaveInstanceState(savedInstanceState: Bundle?) { + savedInstanceState?.let { + mapHolder?.mapView?.onSaveInstanceState(it) + } + } + + fun onLowMemory() { + mapHolder?.mapView?.onLowMemory() + } + + fun onDestroy() { + mapHolder?.mapView?.let { + it.onPause() + it.onStop() + it.onDestroy() + } + } + + class MapItem + class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) { + init { + mapView.onCreate(bundle) + mapView.setOnTouchListener { view, motionEvent -> + // Disallow the touch request for recyclerView scroll + view.parent.requestDisallowInterceptTouchEvent(true) + mapView.onTouchEvent(motionEvent) + true + } + } + } + + class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { + fun bind(item: String) { + textView.text = item + } + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java index c9a9377885..18092ce372 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; -import android.app.Dialog; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -17,9 +16,6 @@ import com.mapbox.mapboxsdk.testapp.R; /** * Test activity showcasing showing a Map inside of a DialogFragment. - * <p> - * Uses the deprecated TextureView API to workaround the issue of seeing a grey background before the gl surface. - * </p> */ public class MapInDialogActivity extends AppCompatActivity { @@ -64,23 +60,6 @@ public class MapInDialogActivity extends AppCompatActivity { mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.OUTDOORS)); } - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new Dialog(getActivity(), getTheme()) { - @Override - public void dismiss() { - if (mapView != null && !mapView.isDestroyed()) { - mapView.onPause(); - mapView.onStop(); - mapView.onDestroy(); - mapView = null; - } - super.dismiss(); - } - }; - } - @Override public void onStart() { super.onStart(); @@ -96,25 +75,20 @@ public class MapInDialogActivity extends AppCompatActivity { @Override public void onPause() { super.onPause(); - if (mapView != null) { - mapView.onPause(); - } + mapView.onPause(); } @Override public void onStop() { super.onStop(); - if (mapView != null) { - mapView.onStop(); - } + mapView.onStop(); } @Override public void onDestroyView() { super.onDestroyView(); - if (mapView != null) { - mapView.onDestroy(); - } + mapView.onDestroy(); + mapView = null; } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt deleted file mode 100644 index 9989d1b137..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.maplayout - -import android.annotation.SuppressLint -import android.os.Bundle -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.TextView -import com.mapbox.mapboxsdk.maps.MapView -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback -import com.mapbox.mapboxsdk.maps.Style -import com.mapbox.mapboxsdk.testapp.R -import kotlinx.android.synthetic.main.activity_recyclerview.* - -/** - * TestActivity showcasing how to integrate a MapView in a RecyclerView. - * <p> - * It requires calling the correct lifecycle methods when detaching and attaching the View to - * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow. - * </p> - */ -@SuppressLint("ClickableViewAccessibility") -class RecyclerViewActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_recyclerview) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.adapter = ItemAdapter(LayoutInflater.from(this), savedInstanceState) - } - - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) - // to save state, we need to call MapView#onSaveInstanceState - (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState) - } - - override fun onLowMemory() { - super.onLowMemory() - // to release memory, we need to call MapView#onLowMemory - (recyclerView.adapter as ItemAdapter).onLowMemory() - } - - override fun onDestroy() { - super.onDestroy() - // to perform cleanup, we need to call MapView#onDestroy - (recyclerView.adapter as ItemAdapter).onDestroy() - } - - class ItemAdapter(private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { - - private val items = listOf( - "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten", - "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", - "nineteen", "twenty", "twenty-one" - ) - - private var mapHolder: MapHolder? = null - - companion object { - const val TYPE_MAP = 0 - const val TYPE_TEXT = 1 - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return if (viewType == TYPE_MAP) { - val mapView = inflater.inflate(R.layout.item_map, parent, false) as MapView - mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } - mapHolder = MapHolder(mapView, savedInstanceState) - return mapHolder as MapHolder - } else { - TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView) - } - } - - override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { - super.onViewAttachedToWindow(holder) - if (holder is MapHolder) { - val mapView = holder.mapView - mapView.onStart() - mapView.onResume() - } - } - - override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { - super.onViewDetachedFromWindow(holder) - if (holder is MapHolder) { - val mapView = holder.mapView - mapView.onPause() - mapView.onStop() - } - } - - override fun getItemCount(): Int { - return items.count() - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - if (holder.itemViewType == TYPE_TEXT) { - val textHolder = holder as TextHolder - textHolder.bind(items[position] as String) - } - } - - override fun getItemViewType(position: Int): Int { - return if (items[position] is MapItem) { - TYPE_MAP - } else { - TYPE_TEXT - } - } - - fun onSaveInstanceState(savedInstanceState: Bundle?){ - savedInstanceState?.let { - mapHolder?.mapView?.onSaveInstanceState(it) - } - } - - fun onLowMemory() { - mapHolder?.mapView?.onLowMemory() - } - - fun onDestroy() { - mapHolder?.mapView?.let { - it.onPause() - it.onStop() - it.onDestroy() - } - } - - class MapItem - class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) { - init { - mapView.onCreate(bundle) - mapView.setOnTouchListener { view, motionEvent -> - // Disallow the touch request for recyclerView scroll - view.parent.requestDisallowInterceptTouchEvent(true) - mapView.onTouchEvent(motionEvent) - true - } - } - } - class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { - fun bind(item: String) { - textView.text = item - } - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt new file mode 100644 index 0000000000..895389bc1e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk.testapp.activity.maplayout + +import android.annotation.SuppressLint +import com.mapbox.mapboxsdk.testapp.R + +/** + * TestActivity showcasing how to integrate a TexureView MapView in a RecyclerView. + */ +@SuppressLint("ClickableViewAccessibility") +class TextureRecyclerViewActivity : GLSurfaceRecyclerViewActivity() { + + override fun getMapItemLayoutId() : Int{ + return R.layout.item_map_texture + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java new file mode 100644 index 0000000000..285d7bc6c8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java @@ -0,0 +1,187 @@ +package com.mapbox.mapboxsdk.testapp.activity.telemetry; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.module.http.HttpRequestUtil; +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import okhttp3.Call; +import okhttp3.EventListener; +import okhttp3.OkHttpClient; +import timber.log.Timber; + +/** + * Test activity showcasing gathering performance measurement data. + */ +public class PerformanceMeasurementActivity extends AppCompatActivity { + + private MapView mapView; + + private Map<String, Long> startTimes = new HashMap<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_map_simple); + mapView = findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.eventListener(new EventListener() { + + @Override + public void callStart(Call call) { + String url = call.request().url().toString(); + startTimes.put(url, System.nanoTime()); + super.callStart(call); + Timber.e("callStart: %s", url); + } + + @Override + public void callEnd(Call call) { + String url = call.request().url().toString(); + Timber.e("callEnd: %s", url); + Long start = startTimes.get(url); + if (start != null) { + long elapsed = System.nanoTime() - start; + triggerPerformanceEvent(url.substring(0, url.indexOf('?')), elapsed); + startTimes.remove(start); + Timber.e("callEnd: %s took %d", url, elapsed); + } + super.callEnd(call); + } + }); + HttpRequestUtil.setOkHttpClient(builder.build()); + + mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle( + new Style.Builder().fromUrl(Style.MAPBOX_STREETS))); + } + + + @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 + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + protected void onDestroy() { + + startTimes.clear(); + + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + private void triggerPerformanceEvent(String style, long elapsed) { + + List<Attribute<String>> attributes = new ArrayList<>(); + attributes.add( + new Attribute<>("style_id", style)); + attributes.add( + new Attribute<>("test_perf_event", "true")); + + List<Attribute<Long>> counters = new ArrayList(); + counters.add(new Attribute<>("elapsed", elapsed)); + + + JsonObject metaData = new JsonObject(); + metaData.addProperty("os", "android"); + metaData.addProperty("manufacturer", Build.MANUFACTURER); + metaData.addProperty("brand", Build.BRAND); + metaData.addProperty("device", Build.MODEL); + metaData.addProperty("version", Build.VERSION.RELEASE); + metaData.addProperty("abi", Build.CPU_ABI); + metaData.addProperty("country", Locale.getDefault().getISO3Country()); + metaData.addProperty("ram", getRam()); + metaData.addProperty("screenSize", getWindowSize()); + + Gson gson = new Gson(); + + Bundle bundle = new Bundle(); + bundle.putString("attributes", gson.toJson(attributes)); + bundle.putString("counters", gson.toJson(counters)); + bundle.putString("metadata", metaData.toString()); + + Mapbox.getTelemetry().onPerformanceEvent(bundle); + } + + private static String getRam() { + ActivityManager actManager = + (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + actManager.getMemoryInfo(memInfo); + return String.valueOf(memInfo.totalMem); + } + + private static String getWindowSize() { + WindowManager windowManager = + (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + int width = metrics.widthPixels; + int height = metrics.heightPixels; + + return "{" + width + "," + height + "}"; + } + + private class Attribute<T> { + private String name; + private T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml index b6b672cf73..10c11a9320 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml @@ -10,6 +10,7 @@ <Button android:layout_width="match_parent" android:layout_height="58dp" android:id="@+id/button" + android:contentDescription="btn_change_fragment" android:text="Replace with empty fragment"/> </FrameLayout>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml new file mode 100644 index 0000000000..4c88a87703 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.mapbox.mapboxsdk.maps.MapView + android:layout_gravity="center" + android:id="@id/mapView" + app:mapbox_cameraZoom="1" + android:layout_width="1080px" + android:layout_height="1920px" + app:mapbox_pixelRatio="1"/> + +</FrameLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml index 53345571b4..f0787ecad9 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> @@ -27,15 +26,4 @@ </LinearLayout> - <android.support.design.widget.FloatingActionButton - android:id="@id/fab" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" - android:layout_margin="@dimen/fab_margin" - android:src="@drawable/ic_add_a_photo_black" - app:backgroundTint="@android:color/white"/> - </RelativeLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml index 3edaff6985..516bf60b6b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent"> <com.mapbox.mapboxsdk.testapp.view.MapViewPager - android:id="@+id/viewpager" + android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml new file mode 100644 index 0000000000..850399e355 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.mapbox.mapboxsdk.maps.MapView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@id/mapView" + android:layout_width="match_parent" + android:layout_height="256dp" + app:mapbox_cameraTargetLat="45.38301927899065" + app:mapbox_cameraTargetLng="8.63525390625" + app:mapbox_cameraZoom="7"/> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml index 3224b73477..3224b73477 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml index a4403a34f7..2c34a59327 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml @@ -15,4 +15,6 @@ <string name="category_storage">Storage</string> <string name="category_textureview">Texture View</string> <string name="category_location">Location</string> + <string name="category_integration">_Integration</string> + <string name="category_telemetry">Telemetry</string> </resources>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 21ebeaabd5..778805b3b3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -78,6 +78,8 @@ <string name="description_location_fragment">Uses LocationComponent in a Fragment</string> <string name="description_location_manual">Force location updates and don\'t rely on the engine</string> <string name="description_location_activation_builder">Use LocationComponentActivationOptions to set options</string> - <string name="description_recyclerview">Show a MapView as a recyclerView item</string> + <string name="description_recyclerview_textureview">Show a TextureView MapView as a recyclerView item</string> + <string name="description_recyclerview_glsurfaceview">Show a GLSurfaceView MapView as a recyclerView item</string> <string name="description_nested_viewpager">Show a MapView inside a viewpager inside a recyclerView</string> + <string name="description_performance_measurement">Show the use PerformanceEvent for performance measurements</string> </resources> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 26f56f29b1..12c82bf21a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -78,6 +78,8 @@ <string name="activity_location_fragment">Location Fragment</string> <string name="activity_location_manual">Manual Location updates</string> <string name="activity_location_activation_builder">Build Location Activation</string> - <string name="activity_recyclerview">RecyclerView</string> + <string name="activity_recyclerview_textureview">RecyclerView TextureView</string> + <string name="activity_recyclerview_glsurfaceview">RecyclerView GLSurfaceView</string> <string name="activity_nested_viewpager">Nested ViewPager</string> + <string name="activity_performance_measurement">Performance Measurement</string> </resources>
\ No newline at end of file diff --git a/platform/android/build.gradle b/platform/android/build.gradle index 5334c93ce9..97f3037afb 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath dependenciesList.bintrayPlugin classpath dependenciesList.artifactoryPlugin classpath dependenciesList.androidPublishPlugin + classpath dependenciesList.jacocoPlugin } } diff --git a/platform/android/gradle/android-nitpick.gradle b/platform/android/gradle/android-nitpick.gradle index f8e4a47b0b..32539270f5 100644 --- a/platform/android/gradle/android-nitpick.gradle +++ b/platform/android/gradle/android-nitpick.gradle @@ -17,6 +17,8 @@ task androidNitpick { verifyVendorSubmodulePin(MAPBOX_JAVA_DIR, MAPBOX_JAVA_TAG_PREFIX, versions.mapboxServices) verifyVendorSubmodulePin(MAPBOX_TELEMETRY_DIR, MAPBOX_TELEMETRY_TAG_PREFIX, versions.mapboxTelemetry) verifyVendorSubmodulePin(MAPBOX_GESTURES_DIR, MAPBOX_GESTURES_TAG_PREFIX, versions.mapboxGestures) + + verifyLicenseGeneration() } } @@ -51,4 +53,12 @@ private def verifyVendorSubmodulePin(def dir, def prefix, def version) { "If you've bumped the pin, make sure to verify the version tag prefix in the android-nitpick.gradle file.") } output.close() +} + +private def verifyLicenseGeneration() { + println "Verify license generation with git diff..." + exec { + workingDir = "${rootDir}" + commandLine "python", "scripts/validate-license.py" + } }
\ No newline at end of file diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 600901ca76..1d17e7f83d 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { versions = [ mapboxServices : '4.3.0', - mapboxTelemetry : '4.2.0', + mapboxTelemetry : '4.3.0', mapboxGestures : '0.4.0', supportLib : '27.1.1', constraintLayout: '1.1.2', @@ -29,7 +29,8 @@ ext { androidPublish : '3.6.2', lint : '26.1.4', gms : '16.0.0', - reLinker : '1.3.1' + reLinker : '1.3.1', + jacoco : '0.8.3' ] dependenciesList = [ @@ -72,6 +73,7 @@ ext { bintrayPlugin : "com.jfrog.bintray.gradle:gradle-bintray-plugin:${versions.bintray}", artifactoryPlugin : "org.jfrog.buildinfo:build-info-extractor-gradle:${versions.artifactory}", androidPublishPlugin : "digital.wup:android-maven-publish:${versions.androidPublish}", + jacocoPlugin : "org.jacoco:org.jacoco.core:${versions.jacoco}", lint : "com.android.tools.lint:lint:${versions.lint}", lintApi : "com.android.tools.lint:lint-api:${versions.lint}", diff --git a/platform/android/gradle/jacoco-report.gradle b/platform/android/gradle/jacoco-report.gradle new file mode 100644 index 0000000000..e50facb683 --- /dev/null +++ b/platform/android/gradle/jacoco-report.gradle @@ -0,0 +1,33 @@ +apply plugin: 'jacoco' +apply from: "${rootDir}/gradle/dependencies.gradle" + +jacoco { + toolVersion = versions.jacoco +} + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { + group = "Reporting" + description = "Combine code coverage to unified report." + + reports { + xml.enabled = true + html.enabled = true + } + + def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes) + def mainSrc = "${project.projectDir}/src/main/java" + println(mainSrc) + def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec") + def execSrc = fileTree(dir: "$project.buildDir", include: "**/*.exec") + + doFirst { + def files = files([ecSrc, execSrc]).files + println "Creating Jacoco Report for ${files.size()} coverage files" + files.each { file -> println file } + } + + sourceDirectories = files([mainSrc]) + classDirectories = files([debugTree]) + executionData = files([ecSrc, execSrc]) +}
\ No newline at end of file diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json index 9e0a1d154f..a6070edccf 100644 --- a/platform/android/scripts/exclude-activity-gen.json +++ b/platform/android/scripts/exclude-activity-gen.json @@ -48,5 +48,7 @@ "EspressoTestActivity", "ChangeResourcesCachePathActivity", "EspressoTestActivity", - "FragmentBackStackActivity" + "FragmentBackStackActivity", + "ChildFragmentMapInDialogActivity", + "PerformanceMeasurementActivity" ] diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 56e7511362..688a3aa527 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -197,7 +197,12 @@ global.defaultValueJava = function(property) { case 'array': switch (property.value) { case 'string': - return '[' + property['default'] + "]"; + case 'enum': + if (property['default'] !== undefined) { + return '[' + property['default'] + ']'; + } else { + return 'new String[0]'; + } case 'number': var result ='new Float[] {'; for (var i = 0; i < property.length; i++) { diff --git a/platform/android/scripts/parse-jacoco-report.py b/platform/android/scripts/parse-jacoco-report.py new file mode 100755 index 0000000000..4d06fda6cc --- /dev/null +++ b/platform/android/scripts/parse-jacoco-report.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import os +import re +from io import open + +reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +with open(reportPath, 'r', encoding='utf-8') as jacocoReport: + line = jacocoReport.readline().strip() + + # find the last INSTRUCTION coverage report which is a sum of all separate ones + instructionIndex = line.rfind('type="INSTRUCTION"') + startIndex = line.find('missed', instructionIndex) + endIndex = line.find('/>', startIndex) + + # find the missed and covered lines counts + numbers = re.match(r'missed="(\d+)" covered="(\d+)"', line[startIndex:endIndex]) + missed = int(numbers.group(1)) + covered = int(numbers.group(2)) + + # calculate the code coverage percentage + percentage = round(covered * 100.0 / (missed + covered), 2) + print("Android tests code coverage: %s%%" % (str(percentage))) + + # invoke the script that send the data to s3 + testEnvironment = "LOCAL" + if os.environ.get('IS_LOCAL_DEVELOPMENT').lower()=='false': + testEnvironment = "CI" + + cmd = os.getcwd() + ("/scripts/code-coverage.sh %.2f %s %s" % (percentage, "Android", testEnvironment)) + os.system(cmd) diff --git a/platform/android/scripts/validate-license.py b/platform/android/scripts/validate-license.py new file mode 100644 index 0000000000..365d7ac265 --- /dev/null +++ b/platform/android/scripts/validate-license.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +from subprocess import call +from subprocess import Popen, PIPE +import sys + +## Run license generation +call('cd ../../ && make android-license', shell=True) + +## Git diff changes +p = Popen(['git', 'diff', '--name-only', 'LICENSE.md'], stdin=PIPE, stdout=PIPE, stderr=PIPE) +output, err = p.communicate(b"input data that is passed to subprocess' stdin") +if "platform/android/LICENSE.md" in output: + raise ValueError("""An error ocurred while validating the license generation. + Changes were detected to the license generation output + but weren't commited. Run make android-license and + commit the changeset to make this validation pass.""")
\ No newline at end of file diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index 4def670f3c..839e6e84dc 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -88,6 +88,17 @@ struct Converter<jni::Local<jni::Object<>>, T, typename std::enable_if_t<std::is } }; +template <class T> +struct Converter<jni::Local<jni::Object<>>, std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>> { + Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const std::vector<T>& value) const { + auto result = jni::Array<jni::String>::New(env, value.size()); + for (std::size_t i = 0; i < value.size(); ++i) { + result.Set(env, i, jni::Make<jni::String>(env, Enum<T>::toString(value.at(i)))); + } + return result; + } +}; + } // namespace conversion } // namespace android } // namespace mbgl diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 4cfb545b84..41081cd0fb 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -3,6 +3,7 @@ #include <mbgl/actor/actor.hpp> #include <mbgl/actor/scheduler.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/resource_transform.hpp> #include <mbgl/util/logging.hpp> @@ -11,6 +12,14 @@ #include "asset_manager_file_source.hpp" namespace mbgl { + +std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) { + auto* assetFileSource = reinterpret_cast<AssetManagerFileSource*>(options.platformContext()); + auto fileSource = std::make_shared<DefaultFileSource>(options.cachePath(), std::unique_ptr<AssetManagerFileSource>(assetFileSource)); + fileSource->setAccessToken(options.accessToken()); + return fileSource; +} + namespace android { // FileSource // @@ -22,15 +31,13 @@ FileSource::FileSource(jni::JNIEnv& _env, std::string path = jni::Make<std::string>(_env, _cachePath); mapbox::sqlite::setTempPath(path); - // Create a core default file source - fileSource = std::make_unique<mbgl::DefaultFileSource>( - path + DATABASE_FILE, - std::make_unique<AssetManagerFileSource>(_env, assetManager)); + resourceOptions + .withAccessToken(accessToken ? jni::Make<std::string>(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE) + .withPlatformContext(reinterpret_cast<void*>(new AssetManagerFileSource(_env, assetManager))); - // Set access token - if (accessToken) { - fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken)); - } + // Create a core default file source + fileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(resourceOptions)); } FileSource::~FileSource() { @@ -110,10 +117,10 @@ FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object<FileSo return reinterpret_cast<FileSource *>(jFileSource.Get(env, field)); } -mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) { +mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) { FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); assert(fileSource != nullptr); - return *fileSource->fileSource; + return fileSource->resourceOptions.clone(); } void FileSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp index 575702120e..3001a5e0f0 100644 --- a/platform/android/src/file_source.hpp +++ b/platform/android/src/file_source.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include "asset_manager.hpp" @@ -49,15 +50,16 @@ public: static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object<FileSource>&); - static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, const jni::Object<FileSource>&); + static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object<FileSource>&); static void registerNative(jni::JNIEnv&); private: const std::string DATABASE_FILE = "/mbgl-offline.db"; optional<int> activationCounter; + mbgl::ResourceOptions resourceOptions; std::unique_ptr<Actor<ResourceTransform>> resourceTransform; - std::unique_ptr<mbgl::DefaultFileSource> fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 3e5b99605e..57265cebb1 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -1,13 +1,15 @@ #pragma once +#include <mbgl/actor/actor_ref.hpp> #include <mbgl/actor/scheduler.hpp> #include <mbgl/util/image.hpp> +#include <mbgl/util/optional.hpp> #include <memory> +#include <mutex> #include <utility> #include <jni/jni.hpp> -#include <mbgl/storage/default_file_source.hpp> namespace mbgl { diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 3a4e2014ba..e74e4c3bbc 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -13,6 +13,7 @@ #include <jni/jni.hpp> +#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/math/minmax.hpp> #include <mbgl/util/constants.hpp> @@ -74,24 +75,22 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env, return; } - // Get native peer for file source - mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource); - // Create a renderer frontend rendererFrontend = std::make_unique<AndroidRendererFrontend>(mapRenderer); // Create Map options MapOptions options; options.withMapMode(MapMode::Continuous) + .withSize(mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) }) + .withPixelRatio(pixelRatio) .withConstrainMode(ConstrainMode::HeightOnly) .withViewportMode(ViewportMode::Default) .withCrossSourceCollisions(_crossSourceCollisions); // Create the core map - map = std::make_unique<mbgl::Map>(*rendererFrontend, *this, - mbgl::Size{ static_cast<uint32_t>(width), - static_cast<uint32_t>(height) }, pixelRatio, - fileSource, *threadPool, options); + map = std::make_unique<mbgl::Map>( + *rendererFrontend, *this, *threadPool, options, + mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource)); } /** diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index d695a91ce0..903543e5d1 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -6,7 +6,6 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/util/run_loop.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/network_status.hpp> #include "annotation/marker.hpp" diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 968c33b644..54b1142845 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -10,20 +10,19 @@ namespace android { // OfflineManager // OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) - : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) { -} + : fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} OfflineManager::~OfflineManager() {} void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { - fileSource.setOfflineMapboxTileCountLimit(limit); + fileSource->setOfflineMapboxTileCountLimit(limit); } void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object<FileSource>& jFileSource_, const jni::Object<ListOfflineRegionsCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); - fileSource.listOfflineRegions([ + fileSource->listOfflineRegions([ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -59,7 +58,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); // Create region - fileSource.createOfflineRegion(definition, metadata, [ + fileSource->createOfflineRegion(definition, metadata, [ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -86,7 +85,7 @@ void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object<Fi auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); auto path = jni::Make<std::string>(env_, jString_); - fileSource.mergeOfflineRegions(path, [ + fileSource->mergeOfflineRegions(path, [ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -226,7 +225,7 @@ void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, response.expires = Timestamp(mbgl::Seconds(expires)); } - fileSource.put(resource, response); + fileSource->put(resource, response); } } // namespace android diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp index f8d57b88da..d0b637b900 100644 --- a/platform/android/src/offline/offline_manager.hpp +++ b/platform/android/src/offline/offline_manager.hpp @@ -1,7 +1,5 @@ #pragma once - -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/offline.hpp> #include <jni/jni.hpp> @@ -10,8 +8,12 @@ #include "offline_region_definition.hpp" #include "../java_types.hpp" +#include <memory> namespace mbgl { + +class DefaultFileSource; + namespace android { class OfflineManager { @@ -85,7 +87,7 @@ public: private: - mbgl::DefaultFileSource& fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; } // namespace android diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index 1cd73a7c76..e0f28631b4 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -14,8 +14,8 @@ namespace android { // OfflineRegion // OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object<FileSource>& jFileSource) - : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)), - fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {} + : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)) + , fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} OfflineRegion::~OfflineRegion() {} @@ -62,7 +62,7 @@ void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Objec }; // Set the observer - fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback))); + fileSource->setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback))); } void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) { @@ -80,13 +80,13 @@ void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState return; } - fileSource.setOfflineRegionDownloadState(*region, state); + fileSource->setOfflineRegionDownloadState(*region, state); } void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object<OfflineRegionStatusCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.getOfflineRegionStatus(*region, [ + fileSource->getOfflineRegionStatus(*region, [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) mutable { @@ -104,7 +104,7 @@ void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object< void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object<OfflineRegionDeleteCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.deleteOfflineRegion(std::move(*region), [ + fileSource->deleteOfflineRegion(std::move(*region), [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](std::exception_ptr error) mutable { @@ -123,7 +123,7 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Ar auto metadata = OfflineRegion::metadata(env_, jMetadata); auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.updateOfflineMetadata(region->getID(), metadata, [ + fileSource->updateOfflineMetadata(region->getID(), metadata, [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](mbgl::expected<mbgl::OfflineRegionMetadata, std::exception_ptr> data) mutable { diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp index 49fa0c8ff8..4618e1abbd 100644 --- a/platform/android/src/offline/offline_region.hpp +++ b/platform/android/src/offline/offline_region.hpp @@ -74,7 +74,7 @@ public: private: std::unique_ptr<mbgl::OfflineRegion> region; - mbgl::DefaultFileSource& fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; } // namespace android diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp index 8eb1d02605..47a2781cb5 100644 --- a/platform/android/src/snapshotter/map_snapshotter.cpp +++ b/platform/android/src/snapshotter/map_snapshotter.cpp @@ -37,7 +37,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, } jFileSource = FileSource::getNativePeer(_env, _jFileSource); - auto& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, _jFileSource); auto size = mbgl::Size { static_cast<uint32_t>(width), static_cast<uint32_t>(height) }; optional<mbgl::CameraOptions> cameraOptions; @@ -56,11 +55,10 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, } else { style = std::make_pair(false, jni::Make<std::string>(_env, styleURL)); } - + showLogo = _showLogo; // Create the core snapshotter - snapshotter = std::make_unique<mbgl::MapSnapshotter>(&fileSource, - threadPool, + snapshotter = std::make_unique<mbgl::MapSnapshotter>(threadPool, style, size, pixelRatio, @@ -69,8 +67,8 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, jni::Make<std::string>(_env, _programCacheDir), _localIdeographFontFamily ? jni::Make<std::string>(_env, _localIdeographFontFamily) : - optional<std::string>{}); - + optional<std::string>{}, + mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource)); } MapSnapshotter::~MapSnapshotter() = default; diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp index 61e4d59326..810848e9cb 100644 --- a/platform/android/src/style/layers/symbol_layer.cpp +++ b/platform/android/src/style/layers/symbol_layer.cpp @@ -176,6 +176,16 @@ namespace android { return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextJustify())); } + jni::Local<jni::Object<>> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextRadialOffset())); + } + + jni::Local<jni::Object<>> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextVariableAnchor())); + } + jni::Local<jni::Object<>> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { using namespace mbgl::android::conversion; return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextAnchor())); @@ -514,6 +524,8 @@ namespace android { METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"), METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"), METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), + METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), + METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"), diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp index f52597ef6f..3b0f8ee5d1 100644 --- a/platform/android/src/style/layers/symbol_layer.hpp +++ b/platform/android/src/style/layers/symbol_layer.hpp @@ -80,6 +80,10 @@ public: jni::Local<jni::Object<jni::ObjectTag>> getTextJustify(jni::JNIEnv&); + jni::Local<jni::Object<jni::ObjectTag>> getTextRadialOffset(jni::JNIEnv&); + + jni::Local<jni::Object<jni::ObjectTag>> getTextVariableAnchor(jni::JNIEnv&); + jni::Local<jni::Object<jni::ObjectTag>> getTextAnchor(jni::JNIEnv&); jni::Local<jni::Object<jni::ObjectTag>> getTextMaxAngle(jni::JNIEnv&); diff --git a/platform/android/vendor/mapbox-events-android b/platform/android/vendor/mapbox-events-android -Subproject 1636d1ae9d5b0f0dd2367c8f32f1af958640b14 +Subproject 5bdf0d90292fb46cd8b1f795763d281b5ac83e0 |