summaryrefslogtreecommitdiff
path: root/platform/android
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/CHANGELOG.md42
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle4
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle1
-rw-r--r--platform/android/MapboxGLAndroidSDK/proguard-rules.pro89
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java148
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java4
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java57
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java65
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java181
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs121
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java162
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs128
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java88
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java78
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml12
-rw-r--r--platform/android/build.gradle1
-rw-r--r--platform/android/config.cmake4
-rw-r--r--platform/android/dependencies.gradle14
-rw-r--r--platform/android/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/scripts/generate-style-code.js93
-rw-r--r--platform/android/scripts/release.py48
-rwxr-xr-xplatform/android/src/jni.cpp3
-rw-r--r--platform/android/src/map/camera_position.cpp7
-rwxr-xr-xplatform/android/src/native_map_view.cpp23
-rwxr-xr-xplatform/android/src/native_map_view.hpp3
-rw-r--r--platform/android/src/style/conversion/position.hpp37
-rw-r--r--platform/android/src/style/conversion/types.hpp7
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp14
-rw-r--r--platform/android/src/style/light.cpp146
-rw-r--r--platform/android/src/style/light.cpp.ejs123
-rw-r--r--platform/android/src/style/light.hpp57
-rw-r--r--platform/android/src/style/light.hpp.ejs59
-rw-r--r--platform/android/src/style/position.cpp34
-rw-r--r--platform/android/src/style/position.hpp29
75 files changed, 2331 insertions, 378 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 7807334c14..a9d31426c3 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -3,11 +3,51 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## 5.1.0 - TBA
+* Fix tracking mode + camera race condition [#9133](https://github.com/mapbox/mapbox-gl-native/pull/9133)
+* Harden orientation changes [#9128](https://github.com/mapbox/mapbox-gl-native/pull/9128)
+
+## 5.1.0-beta.3 - May 26, 2017
+
+* Add binding support for Light [#9013](https://github.com/mapbox/mapbox-gl-native/pull/9013)
* Update attribution with new Mapbox wordmark [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774)
+* LatLngBounds bearing default value [#9102](https://github.com/mapbox/mapbox-gl-native/pull/9102)
+* Stop location updates when toggling MyLocationView [#9099](https://github.com/mapbox/mapbox-gl-native/pull/9099)
+* Horizontally rotated in snapshot [#9083](https://github.com/mapbox/mapbox-gl-native/pull/9083)
+* Disable letter spacing for Arabic text [#9071](https://github.com/mapbox/mapbox-gl-native/pull/9071)
+* Correct bearing conversion when animating the map [#9050](https://github.com/mapbox/mapbox-gl-native/pull/9050)
+* Don't leak selected markers when removing [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047)
+* Bump tools and support lib version [#9046](https://github.com/mapbox/mapbox-gl-native/pull/9046)
+* MarkerView deselect events with OnMarkerViewClickListener [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047)
+* LOST update to v3.0.0 [#9112](https://github.com/mapbox/mapbox-gl-native/pull/9112)
+* Convert dp to pixels for meters per pixel at latitude [#9048](https://github.com/mapbox/mapbox-gl-native/pull/9048)
+
+## 5.1.0-beta.2 - May 12, 2017
+
+5.1.0-beta.2 builds further on 5.1.0-beta.1 and adds:
+
+* When a layer is added, reload its source's tiles [#8963](https://github.com/mapbox/mapbox-gl-native/pull/8963)
+* Update release script to support CircleCI builds [#8950](https://github.com/mapbox/mapbox-gl-native/pull/8950)
+* URL getter on Sources [#8959](https://github.com/mapbox/mapbox-gl-native/pull/8959)
+* Build SNAPSHOT from release branch CI configuration [#8958](https://github.com/mapbox/mapbox-gl-native/pull/8958)
+* Fix UI test filter in Makefile [#8960](https://github.com/mapbox/mapbox-gl-native/pull/8960)
+* Bump & fixup dependencies [#8921](https://github.com/mapbox/mapbox-gl-native/pull/8921)
+* Ignore already deleted region [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920)
+* Keep offline observer when timeout occurs [#8919](https://github.com/mapbox/mapbox-gl-native/pull/8919)
+* Show error message when no browser installed [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920)
+* Reset observers of removed Sources and Layers [#8900](https://github.com/mapbox/mapbox-gl-native/pull/8900)
+* Only build custom layer .so for debug builds [#8885](https://github.com/mapbox/mapbox-gl-native/pull/8885)
+* Update localizations [#8883](https://github.com/mapbox/mapbox-gl-native/pull/8883)
+* Reset observers of removed Sources and Layers [#8862](https://github.com/mapbox/mapbox-gl-native/pull/8862)
+* Remove force style cascade [#8866](https://github.com/mapbox/mapbox-gl-native/pull/8866)
+* Update proguard config [#8944](https://github.com/mapbox/mapbox-gl-native/pull/8944)
+* Update LOST to 2.3.0-SNAPSHOT [#8872](https://github.com/mapbox/mapbox-gl-native/pull/8872)
+* Update logo [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774)
+* Camera change listener v2.0 [#8644](https://github.com/mapbox/mapbox-gl-native/pull/8644)
+* Allow filesource url transform reset [#8957](https://github.com/mapbox/mapbox-gl-native/pull/8957)
## 5.1.0-beta.1 - May 2, 2017
-5.1.0 builds further on 5.0.2 and adds:
+5.1.0-beta.1 builds further on 5.0.2 and adds:
* Support for FillExtrusionLayer [#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431)
* Limit Viewport [#8622](https://github.com/mapbox/mapbox-gl-native/pull/8622)
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 40712da065..adbc7cad7f 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -95,6 +95,9 @@ android {
}
}
}
+
+ // proguard config for .aar
+ consumerProguardFiles 'proguard-rules.pro'
}
// avoid naming conflicts, force usage of prefix
@@ -126,7 +129,6 @@ android {
release {
// aar proguard configuration
- consumerProguardFiles 'proguard-rules.pro'
jniDebuggable false
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
index 05037c6be7..e0bc076d3d 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
@@ -15,6 +15,7 @@ task checkstyle(type: Checkstyle) {
exclude '**/style/layers/Property.java'
exclude '**/style/layers/PropertyFactory.java'
exclude '**/style/layers/*Layer.java'
+ exclude '**/style/light/Light.java'
classpath = files()
ignoreFailures = false
}
diff --git a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
index baecd80e50..8e47815451 100644
--- a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
@@ -2,89 +2,8 @@
# in ../sdk/tools/proguard/proguard-android.txt,
# contents of this file will be appended into proguard-android.txt
-keepattributes Signature, *Annotation*, EnclosingMethod
-
-# Square okio, ignoring warnings,
-# see https://github.com/square/okio/issues/60
--dontwarn okhttp3.**
--dontwarn okio.**
-
-# Gesture package
-keep class almeros.android.multitouch.gesturedetectors.** { *; }
-
-# Package annotations
--keep class com.mapbox.mapboxsdk.annotations.** { *; }
-
-# Package camera
--keep class com.mapbox.mapboxsdk.camera.** { *; }
-
-# Package geometry
--keep class com.mapbox.mapboxsdk.geometry.** { *; }
-
-# Package http
--keep class com.mapbox.mapboxsdk.http.** { *; }
-
-# Package maps
--keep class com.mapbox.mapboxsdk.maps.** { *; }
-
-# Package net
--keep class com.mapbox.mapboxsdk.net.** { *; }
-
-# Package offline
--keep class com.mapbox.mapboxsdk.offline.** { *; }
-
-# Package storage
--keep class com.mapbox.mapboxsdk.storage.** { *; }
-
-# Package style
--keep class com.mapbox.mapboxsdk.style.layers.** { *; }
--keep class com.mapbox.mapboxsdk.style.sources.** { *; }
--keep class com.mapbox.mapboxsdk.style.functions.** { *; }
-
-# Package telemetry
--keep class com.mapbox.mapboxsdk.telemetry.** { *; }
-
-#
-# Mapbox-java Proguard rules
-# We include these rules since libjava is a Jar file not AAR
-#
-
-# Retrofit 2
-# Platform calls Class.forName on types which do not exist on Android to determine platform.
--dontnote retrofit2.Platform
-# Platform used when running on RoboVM on iOS. Will not be used at runtime.
--dontnote retrofit2.Platform$IOS$MainThreadExecutor
-# Platform used when running on Java 8 VMs. Will not be used at runtime.
--dontwarn retrofit2.Platform$Java8
-# Retain generic type information for use by reflection by converters and adapters.
--keepattributes Signature
-# Retain declared checked exceptions for use by a Proxy instance.
--keepattributes Exceptions
-
-# For using GSON @Expose annotation
--keepattributes *Annotation*
-# Gson specific classes
--dontwarn sun.misc.**
-
-# Prevent proguard from stripping interface information from TypeAdapterFactory,
-# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
--keep class * implements com.google.gson.TypeAdapterFactory
--keep class * implements com.google.gson.JsonSerializer
--keep class * implements com.google.gson.JsonDeserializer
-
-# MAS Data Models
--keep class com.mapbox.services.commons.geojson.** { *; }
--keep class com.mapbox.services.mapmatching.v4.models.** { *; }
--keep class com.mapbox.services.distance.v1.models.** { *; }
--keep class com.mapbox.services.directions.v4.models.** { *; }
--keep class com.mapbox.services.directions.v5.models.** { *; }
--keep class com.mapbox.services.geocoding.v5.models.** { *; }
-
--dontwarn javax.annotation.**
-
--keepclassmembers class rx.internal.util.unsafe.** {
- long producerIndex;
- long consumerIndex;
-}
-
--keep class com.google.** { *; }
--dontwarn com.google.** \ No newline at end of file
+-keep class com.mapbox.mapboxsdk.** { *; }
+-keep interface com.mapbox.mapboxsdk.** { *; }
+-keep class com.mapbox.services.android.telemetry.** { *; }
+-keep class com.mapbox.services.commons.** { *;} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index 8098ee4d86..81134e9497 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk;
+import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -15,6 +16,14 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
+/**
+ * The entry point of the Mapbox Android SDK.
+ * <p>
+ * Obtain a reference by calling {@link #getInstance(Context, String)}. Usually this class is configured in
+ * {@link Application#onCreate()} and is responsible for the active access token, application context, and
+ * connectivity state.
+ * </p>
+ */
public final class Mapbox {
private static Mapbox INSTANCE;
@@ -25,7 +34,7 @@ public final class Mapbox {
/**
* Get an instance of Mapbox.
* <p>
- * This class manages the active access token, application context and connectivity state.
+ * This class manages the active access token, application context, and connectivity state.
* </p>
*
* @param context Android context which holds or is an application context
@@ -52,9 +61,9 @@ public final class Mapbox {
}
/**
- * Access Token for this application.
+ * Access token for this application.
*
- * @return Mapbox Access Token
+ * @return Mapbox access token
*/
public static String getAccessToken() {
validateMapbox();
@@ -72,7 +81,7 @@ public final class Mapbox {
}
/**
- * Runtime validation of Access Token.
+ * Runtime validation of access token.
*
* @throws MapboxConfigurationException exception thrown when not using a valid accessToken
*/
@@ -92,11 +101,11 @@ public final class Mapbox {
}
/**
- * Manually sets the connectivity state of the app. This is useful for apps that control their
+ * Manually sets the connectivity state of the app. This is useful for apps which control their
* own connectivity state and want to bypass any checks to the ConnectivityManager.
*
* @param connected flag to determine the connectivity state, true for connected, false for
- * disconnected, null for ConnectivityManager to determine.
+ * disconnected, and null for ConnectivityManager to determine.
*/
public static synchronized void setConnected(Boolean connected) {
// Connectivity state overridden by app
@@ -104,10 +113,10 @@ public final class Mapbox {
}
/**
- * Determines whether we have an Internet connection available. Please do not rely on this
- * method in your apps, this method is used internally by the SDK.
+ * Determines whether we have an internet connection available. Please do not rely on this
+ * method in your apps. This method is used internally by the SDK.
*
- * @return true if there is an Internet connection, false otherwise
+ * @return true if there is an internet connection, false otherwise
*/
public static synchronized Boolean isConnected() {
if (INSTANCE.connected != null) {
@@ -119,4 +128,4 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
index b1a05ec436..2ee17c227d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
@@ -1,15 +1,18 @@
package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
+import android.util.DisplayMetrics;
-import com.mapbox.mapboxsdk.maps.MapView;
+import java.nio.ByteBuffer;
/**
- * Icon is the visual representation of a {@link Marker} on a {@link MapView}.
+ * Icon is the visual representation of a Marker on a MapView.
*
* @see Marker
+ * @see IconFactory
*/
public class Icon {
+
private Bitmap mBitmap;
private String mId;
@@ -19,29 +22,67 @@ public class Icon {
}
/**
- * {@link String} identifier for this {@link Icon}.
+ * String identifier for this icon.
*
- * @return {@link String} identifier for this {@link Icon}.
+ * @return String identifier for this icon.
*/
public String getId() {
return mId;
}
/**
- * Get the {@link Bitmap} being used for this {@link Icon}.
+ * Get the bitmap being used for this icon.
*
- * @return The {@link Bitmap} being used for the {@link Icon}.
+ * @return The bitmap being used for the icon.
*/
public Bitmap getBitmap() {
+ if (mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
+ mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false);
+ }
return mBitmap;
}
/**
- * Compares this {@link Icon} object with another {@link Icon} and determines if they match.
+ * Get the icon bitmap scale.
+ * <p>
+ * Requires the bitmap to be set before calling this method.
+ * </p>
+ *
+ * @return the scale of the bitmap
+ */
+ public float getScale() {
+ if (mBitmap == null) {
+ throw new IllegalStateException("Required to set a Icon before calling getScale");
+ }
+ float density = mBitmap.getDensity();
+ if (density == Bitmap.DENSITY_NONE) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ }
+ return density / DisplayMetrics.DENSITY_DEFAULT;
+ }
+
+ /**
+ * Get the icon bitmap bytes.
+ * <p>
+ * Requires the bitmap to be set before calling this method.
+ * </p>
*
- * @param object Another {@link Icon} to compare with this object.
- * @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else,
- * false.
+ * @return the bytes of the bitmap
+ */
+ public byte[] toBytes() {
+ if (mBitmap == null) {
+ throw new IllegalStateException("Required to set a Icon before calling toBytes");
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight());
+ mBitmap.copyPixelsToBuffer(buffer);
+ return buffer.array();
+ }
+
+ /**
+ * Compares this icon object with another icon and determines if they match.
+ *
+ * @param object Another iconi to compare with this object.
+ * @return True if the icon being passed in matches this icon object. Else, false.
*/
@Override
public boolean equals(Object object) {
@@ -53,11 +94,7 @@ public class Icon {
}
Icon icon = (Icon) object;
-
- if (!mBitmap.equals(icon.mBitmap)) {
- return false;
- }
- return mId.equals(icon.mId);
+ return mBitmap.equals(icon.mBitmap) && mId.equals(icon.mId);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index 30336d4ebd..56e8cc4ce2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -361,6 +362,9 @@ public class MarkerView extends Marker {
*/
@Override
public Icon getIcon() {
+ if (markerViewIcon == null) {
+ setIcon(IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarkerView());
+ }
return markerViewIcon;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index 5e958ff565..66c261f1d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -156,7 +156,7 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Builder for composing {@link CameraPosition} objects.
+ * Builder for composing CameraPosition objects.
*/
public static final class Builder {
@@ -190,7 +190,7 @@ public final class CameraPosition implements Parcelable {
/**
* Create Builder with an existing CameraPosition data.
*
- * @param typedArray TypedArray containgin attribute values
+ * @param typedArray TypedArray containing attribute values
*/
public Builder(TypedArray typedArray) {
super();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index 64b86054a0..8e1411e273 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -15,7 +15,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Factory for creating {@link CameraUpdate} objects.
+ * Factory for creating CameraUpdate objects.
*/
public final class CameraUpdateFactory {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
index f53c65d055..88c3bef673 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
@@ -16,7 +16,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyBearingTracking {
/**
- * Indicates the parameter accepts one of the values from {@link MyBearingTracking}.
+ * Indicates that the parameter accepts one of the values from MyBearingTracking.
*/
@IntDef( {NONE, COMPASS, GPS, /**COMBINED**/})
@Retention(RetentionPolicy.SOURCE)
@@ -38,6 +38,4 @@ public class MyBearingTracking {
*/
public static final int GPS = 0x00000008;
- // public static final int COMBINED = 0x00000012;
-
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
index 39f653596f..a1744d701f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
@@ -17,7 +17,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyLocationTracking {
/**
- * Indicates the parameter accepts one of the values from {@link MyLocationTracking}.
+ * Indicates the parameter accepts one of the values from MyLocationTracking.
*/
@IntDef( {TRACKING_NONE, TRACKING_FOLLOW})
@Retention(RetentionPolicy.SOURCE)
@@ -30,7 +30,7 @@ public class MyLocationTracking {
public static final int TRACKING_NONE = 0x00000000;
/**
- * Tracking the location of the user, {@link MapView} will reposition to center of {@link MyLocationView}
+ * Tracking the location of the user. {@link MapView} will reposition to center of {@link MyLocationView}
*/
public static final int TRACKING_FOLLOW = 0x00000004;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
index 77d0929df3..31e6313509 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
@@ -19,7 +19,7 @@ public class Style {
/**
- * Indicates the parameter accepts one of the values from {@link Style}. Using one of these
+ * Indicates the parameter accepts one of the values from Style. Using one of these
* constants means your map style will always use the latest version and may change as we
* improve the style
*/
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
index b795cf1d5b..4e934fa3cc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
@@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location;
import android.content.Context;
import android.location.Location;
-import android.util.Log;
+import android.support.annotation.NonNull;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
@@ -15,6 +15,8 @@ import com.mapzen.android.lost.api.LostApiClient;
import java.lang.ref.WeakReference;
+import timber.log.Timber;
+
/**
* Manages locational updates. Contains methods to register and unregister location listeners.
* <ul>
@@ -33,8 +35,6 @@ import java.lang.ref.WeakReference;
public class LocationSource extends LocationEngine implements
LostApiClient.ConnectionCallbacks, LocationListener {
- private static final String LOG_TAG = LocationSource.class.getSimpleName();
-
private static LocationEngine instance;
private WeakReference<Context> context;
@@ -48,7 +48,13 @@ public class LocationSource extends LocationEngine implements
.build();
}
- public static synchronized LocationEngine getLocationEngine(Context context) {
+ /**
+ * Get the LocationEngine instance.
+ *
+ * @param context a Context from which the application context is derived
+ * @return the LocationEngine instance
+ */
+ public static synchronized LocationEngine getLocationEngine(@NonNull Context context) {
if (instance == null) {
instance = new LocationSource(context.getApplicationContext());
}
@@ -56,6 +62,10 @@ public class LocationSource extends LocationEngine implements
return instance;
}
+ /**
+ * Activate the location engine which will connect whichever location provider you are using. You'll need to call
+ * this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}.
+ */
@Override
public void activate() {
if (lostApiClient != null && !lostApiClient.isConnected()) {
@@ -63,6 +73,11 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Disconnect the location engine which is useful when you no longer need location updates or requesting the users
+ * {@link LocationEngine#getLastLocation()}. Before deactivating, you'll need to stop request user location updates
+ * using {@link LocationEngine#removeLocationUpdates()}.
+ */
@Override
public void deactivate() {
if (lostApiClient != null && lostApiClient.isConnected()) {
@@ -70,11 +85,20 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Check if your location provider has been activated/connected. This is mainly used internally but is also useful in
+ * the rare case when you'd like to know if your location engine is connected or not.
+ *
+ * @return boolean true if the location engine has been activated/connected, else false.
+ */
@Override
public boolean isConnected() {
return lostApiClient.isConnected();
}
+ /**
+ * Invoked when the location provider has connected.
+ */
@Override
public void onConnected() {
for (LocationEngineListener listener : locationListeners) {
@@ -82,11 +106,19 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Invoked when the location provider connection has been suspended.
+ */
@Override
public void onConnectionSuspended() {
- Log.d(LOG_TAG, "Connection suspended.");
+ Timber.d("Connection suspended.");
}
+ /**
+ * Returns the Last known location is the location provider is connected and location permissions are granted.
+ *
+ * @return the last known location
+ */
@Override
public Location getLastLocation() {
if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
@@ -97,6 +129,9 @@ public class LocationSource extends LocationEngine implements
return null;
}
+ /**
+ * Request location updates to the location provider.
+ */
@Override
public void requestLocationUpdates() {
// Common params
@@ -122,6 +157,9 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Dismiss ongoing location update to the location provider.
+ */
@Override
public void removeLocationUpdates() {
if (lostApiClient.isConnected()) {
@@ -129,20 +167,15 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Invoked when the Location has changed.
+ *
+ * @param location the new location
+ */
@Override
public void onLocationChanged(Location location) {
for (LocationEngineListener listener : locationListeners) {
listener.onLocationChanged(location);
}
}
-
- @Override
- public void onProviderDisabled(String provider) {
- Log.d(LOG_TAG, "Provider disabled: " + provider);
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- Log.d(LOG_TAG, "Provider enabled: " + provider);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 9b6706b90c..7e7947047e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -100,6 +100,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -112,6 +116,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -124,6 +132,7 @@ class AnnotationManager {
Annotation annotation;
int count = annotationsArray.size();
long[] ids = new long[count];
+ selectedMarkers.clear();
for (int i = 0; i < count; i++) {
ids[i] = annotationsArray.keyAt(i);
annotation = annotationsArray.get(ids[i]);
@@ -383,12 +392,15 @@ class AnnotationManager {
for (Marker nearbyMarker : nearbyMarkers) {
for (Marker selectedMarker : selectedMarkers) {
if (nearbyMarker.equals(selectedMarker)) {
- if (onMarkerClickListener != null) {
- // end developer has provided a custom click listener
+ if (nearbyMarker instanceof MarkerView) {
+ handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) nearbyMarker);
+ } else if (onMarkerClickListener != null) {
handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
- if (!handledDefaultClick) {
- deselectMarker(nearbyMarker);
- }
+ }
+
+ if (!handledDefaultClick) {
+ // only deselect marker if user didn't handle the click event themselves
+ deselectMarker(nearbyMarker);
}
return true;
}
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
new file mode 100644
index 0000000000..bd028aecb6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -0,0 +1,67 @@
+package com.mapbox.mapboxsdk.maps;
+
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
+
+class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
+ MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
+
+ private boolean idle = true;
+
+ private OnCameraMoveStartedListener onCameraMoveStartedListener;
+ private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
+ private OnCameraMoveListener onCameraMoveListener;
+ private OnCameraIdleListener onCameraIdleListener;
+
+ void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
+ this.onCameraMoveStartedListener = onCameraMoveStartedListener;
+ }
+
+ void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
+ this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
+ }
+
+ void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
+ this.onCameraMoveListener = onCameraMoveListener;
+ }
+
+ void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
+ this.onCameraIdleListener = onCameraIdleListener;
+ }
+
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ if (!idle) {
+ return;
+ }
+
+ idle = false;
+ if (onCameraMoveStartedListener != null) {
+ onCameraMoveStartedListener.onCameraMoveStarted(reason);
+ }
+ }
+
+ @Override
+ public void onCameraMove() {
+ if (onCameraMoveListener != null && !idle) {
+ onCameraMoveListener.onCameraMove();
+ }
+ }
+
+ @Override
+ public void onCameraMoveCanceled() {
+ if (onCameraMoveCanceledListener != null && !idle) {
+ onCameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+ }
+
+ @Override
+ public void onCameraIdle() {
+ if (onCameraIdleListener != null && !idle) {
+ idle = true;
+ onCameraIdleListener.onCameraIdle();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
index 006122a4e2..aec9a848b7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
@@ -2,6 +2,9 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
+/**
+ * Interface definition of a callback that is invoked when the focal point will change.
+ */
public interface FocalPointChangeListener {
void onFocalPointChanged(PointF pointF);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
index c9d81a88bc..9f4171aee8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
@@ -1,15 +1,14 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
-import android.util.DisplayMetrics;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -41,118 +40,109 @@ class IconManager {
Icon loadIconForMarker(Marker marker) {
Icon icon = marker.getIcon();
-
- // calculating average before adding
- int iconSize = icons.size() + 1;
-
- // TODO replace former if case with anchor implementation,
- // current workaround for having extra pixels is diving height by 2
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- marker.setIcon(icon);
- } else {
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- }
-
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
+ // TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2
+ // TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
+ icon = loadDefaultIconForMarker(marker);
} else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ updateAverageIconSize(icon);
}
+ addIcon(icon);
return icon;
}
- Icon loadIconForMarkerView(MarkerView marker) {
+ void loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
- int iconSize = icons.size() + 1;
- if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView();
- marker.setIcon(icon);
- }
Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- if (!icons.contains(icon)) {
- icons.add(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
- return icon;
+ updateAverageIconSize(bitmap);
+ addIcon(icon, false);
}
int getTopOffsetPixelsForIcon(Icon icon) {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
- void loadIcon(Icon icon) {
+ int getAverageIconHeight() {
+ return averageIconHeight;
+ }
+
+ int getAverageIconWidth() {
+ return averageIconWidth;
+ }
+
+ private Icon loadDefaultIconForMarker(Marker marker) {
+ Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
- String id = icon.getId();
- if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- }
- ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
- bitmap.copyPixelsToBuffer(buffer);
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
+ marker.setIcon(icon);
+ return icon;
+ }
+
+ private void addIcon(Icon icon) {
+ addIcon(icon, true);
+ }
- float density = bitmap.getDensity();
- if (density == Bitmap.DENSITY_NONE) {
- density = DisplayMetrics.DENSITY_DEFAULT;
+ private void addIcon(Icon icon, boolean addIconToMap) {
+ if (!icons.contains(icon)) {
+ icons.add(icon);
+ if (addIconToMap) {
+ loadIcon(icon);
+ }
+ } else {
+ validateIconChanged(icon);
}
- float scale = density / DisplayMetrics.DENSITY_DEFAULT;
- nativeMapView.addAnnotationIcon(
- id,
+ }
+
+ private void updateAverageIconSize(Icon icon) {
+ updateAverageIconSize(icon.getBitmap());
+ }
+
+ private void updateAverageIconSize(Bitmap bitmap) {
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
+ }
+
+ private void updateAverageIconSize(int width, int height) {
+ int iconSize = icons.size() + 1;
+ averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
+ averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
+ }
+
+ private void loadIcon(Icon icon) {
+ Bitmap bitmap = icon.getBitmap();
+ nativeMapView.addAnnotationIcon(icon.getId(),
bitmap.getWidth(),
bitmap.getHeight(),
- scale, buffer.array());
+ icon.getScale(),
+ icon.toBytes());
}
void reloadIcons() {
- int count = icons.size();
- for (int i = 0; i < count; i++) {
- Icon icon = icons.get(i);
+ for (Icon icon : icons) {
loadIcon(icon);
}
}
+ private void validateIconChanged(Icon icon) {
+ Icon oldIcon = icons.get(icons.indexOf(icon));
+ if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
+ throw new IconBitmapChangedException();
+ }
+ }
+
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- marker.setIcon(icon);
- }
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ icon = loadDefaultIconForMarker(marker);
}
+ addIcon(icon);
+ setTopOffsetPixels(marker, mapboxMap, icon);
+ }
+ private void setTopOffsetPixels(Marker marker, MapboxMap mapboxMap, Icon icon) {
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
-
- int getAverageIconHeight() {
- return averageIconHeight;
- }
-
- int getAverageIconWidth() {
- return averageIconWidth;
- }
}
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 80fd6248bc..33e13c5ecc 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
@@ -22,6 +22,8 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.utils.MathUtils;
import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
+
/**
* Manages gestures events on a MapView.
* <p>
@@ -35,6 +37,7 @@ final class MapGestureDetector {
private final UiSettings uiSettings;
private final TrackingSettings trackingSettings;
private final AnnotationManager annotationManager;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final GestureDetectorCompat gestureDetector;
private final ScaleGestureDetector scaleGestureDetector;
@@ -56,12 +59,14 @@ final class MapGestureDetector {
private boolean scaleGestureOccurred = false;
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
- TrackingSettings trackingSettings, AnnotationManager annotationManager) {
+ TrackingSettings trackingSettings, AnnotationManager annotationManager,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.annotationManager = annotationManager;
this.transform = transform;
this.projection = projection;
this.uiSettings = uiSettings;
this.trackingSettings = trackingSettings;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
// Touch gesture detectors
gestureDetector = new GestureDetectorCompat(context, new GestureListener());
@@ -187,6 +192,7 @@ final class MapGestureDetector {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
getLocationFromGesture(event.getX(), event.getY()), transform));
scrollInProgress = false;
+ cameraChangeDispatcher.onCameraIdle();
}
twoTap = false;
@@ -273,6 +279,9 @@ final class MapGestureDetector {
break;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
// Single finger double tap
if (focalPoint != null) {
// User provided focal point
@@ -337,6 +346,7 @@ final class MapGestureDetector {
// and ignore when a scale gesture has occurred
return false;
}
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
float screenDensity = uiSettings.getPixelRatio();
@@ -362,9 +372,7 @@ final class MapGestureDetector {
long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE);
// update transformation
- transform.setGestureInProgress(true);
transform.moveBy(offsetX, offsetY, animationTime);
- transform.setGestureInProgress(false);
if (onFlingListener != null) {
onFlingListener.onFling();
@@ -375,12 +383,6 @@ final class MapGestureDetector {
// Called for drags
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (!scrollInProgress) {
- scrollInProgress = true;
- MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
- getLocationFromGesture(e1.getX(), e1.getY()),
- MapboxEvent.GESTURE_PAN_START, transform));
- }
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
}
@@ -389,10 +391,19 @@ final class MapGestureDetector {
return false;
}
+ if (!scrollInProgress) {
+ scrollInProgress = true;
+
+ // Cancel any animation
+ transform.cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
+ getLocationFromGesture(e1.getX(), e1.getY()),
+ MapboxEvent.GESTURE_PAN_START, transform));
+ }
+
// reset tracking if needed
trackingSettings.resetTrackingModesIfRequired(true, false, false);
- // Cancel any animation
- transform.cancelTransitions();
// Scroll the map
transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/);
@@ -446,6 +457,8 @@ final class MapGestureDetector {
// If scale is large enough ignore a tap
scaleFactor *= detector.getScaleFactor();
if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
zoomStarted = true;
}
@@ -465,9 +478,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Gesture is a quickzoom if there aren't two fingers
quickZoom = !twoTap;
@@ -512,6 +522,9 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -522,6 +535,7 @@ final class MapGestureDetector {
// Called when the fingers leave the screen
@Override
public void onRotateEnd(RotateGestureDetector detector) {
+ // notify camera change listener
beginTime = 0;
totalAngle = 0.0f;
started = false;
@@ -553,13 +567,8 @@ final class MapGestureDetector {
if (!started) {
return false;
}
-
- // Cancel any animation
- transform.cancelTransitions();
-
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
-
trackingSettings.resetTrackingModesIfRequired(true, true, false);
// Get rotate value
@@ -593,6 +602,8 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -633,9 +644,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Get tilt value (scale and clamp)
double pitch = transform.getTilt();
pitch -= 0.1 * detector.getShovePixelsDelta();
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 4f90b0a8fe..cf1841e180 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
@@ -131,6 +131,9 @@ public class MapView extends FrameLayout {
// callback for zooming in the camera
CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
+ // callback for camera change events
+ CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
+
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
@@ -145,13 +148,14 @@ public class MapView extends FrameLayout {
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
markerViewManager, iconManager, annotations, markers, polygons, polylines);
- Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings);
+ Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
+ cameraChangeDispatcher);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
- registerTouchListener, annotationManager);
+ registerTouchListener, annotationManager, cameraChangeDispatcher);
// user input
mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
- annotationManager);
+ annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
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 5f1ed0755c..f60ddf616a 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
@@ -41,6 +41,7 @@ import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
@@ -69,6 +70,7 @@ public final class MapboxMap {
private final Transform transform;
private final AnnotationManager annotationManager;
private final MyLocationViewSettings myLocationViewSettings;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final OnRegisterTouchListener onRegisterTouchListener;
@@ -76,7 +78,7 @@ public final class MapboxMap {
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
- AnnotationManager annotations) {
+ AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) {
this.nativeMapView = map;
this.uiSettings = ui;
this.trackingSettings = tracking;
@@ -85,6 +87,7 @@ public final class MapboxMap {
this.annotationManager = annotations.bind(this);
this.transform = transform;
this.onRegisterTouchListener = listener;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) {
@@ -566,6 +569,20 @@ public final class MapboxMap {
}
//
+ //
+ //
+
+ /**
+ * Get the global light source used to change lighting conditions on extruded fill layers.
+ *
+ * @return the global light source
+ */
+ @Nullable
+ public Light getLight() {
+ return nativeMapView.getLight();
+ }
+
+ //
// Camera API
//
@@ -1623,11 +1640,52 @@ public final class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
+ @Deprecated
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
transform.setOnCameraChangeListener(listener);
}
/**
+ * Sets a callback that is invoked when camera movement has ended.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
+ cameraChangeDispatcher.setOnCameraIdleListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement was cancelled.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement has started.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera position changes.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveListener(listener);
+ }
+
+ /**
* Sets a callback that's invoked on every frame rendered to the map view.
*
* @param listener The callback that's invoked on every frame rendered to the map view.
@@ -1941,7 +1999,12 @@ public final class MapboxMap {
/**
* Interface definition for a callback to be invoked when the camera changes position.
+ *
+ * @deprecated Replaced by {@link MapboxMap.OnCameraMoveStartedListener}, {@link MapboxMap.OnCameraMoveListener} and
+ * {@link MapboxMap.OnCameraIdleListener}. The order in which the deprecated onCameraChange method will be called in
+ * relation to the methods in the new camera change listeners is undefined.
*/
+ @Deprecated
public interface OnCameraChangeListener {
/**
* Called after the camera position has changed. During an animation,
@@ -1954,6 +2017,56 @@ public final class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked for when the camera motion starts.
+ */
+ public interface OnCameraMoveStartedListener {
+ int REASON_API_GESTURE = 1;
+ int REASON_DEVELOPER_ANIMATION = 2;
+ int REASON_API_ANIMATION = 3;
+
+ /**
+ * Called when the camera starts moving after it has been idle or when the reason for camera motion has changed.
+ *
+ * @param reason the reason for the camera change
+ */
+ void onCameraMoveStarted(int reason);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera changes position.
+ */
+ public interface OnCameraMoveListener {
+ /**
+ * Called repeatedly as the camera continues to move after an onCameraMoveStarted call.
+ * This may be called as often as once every frame and should not perform expensive operations.
+ */
+ void onCameraMove();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera's motion has been stopped or when the camera
+ * starts moving for a new reason.
+ */
+ public interface OnCameraMoveCanceledListener {
+ /**
+ * Called when the developer explicitly calls the cancelTransitions() method or if the reason for camera motion has
+ * changed before the onCameraIdle had a chance to fire after the previous animation.
+ * Do not update or animate the camera from within this method.
+ */
+ void onCameraMoveCanceled();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when camera movement has ended.
+ */
+ public interface OnCameraIdleListener {
+ /**
+ * Called when camera movement has ended.
+ */
+ void onCameraIdle();
+ }
+
+ /**
* Interface definition for a callback to be invoked when a frame is rendered to the map view.
*
* @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index 68603ab1a3..98f94ddb39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -36,7 +36,7 @@ import java.util.Arrays;
public class MapboxMapOptions implements Parcelable {
private static final float FOUR_DP = 4f;
- private static final float EIGHTY_NINE_DP = 92f;
+ private static final float NINETY_TWO_DP = 92f;
private CameraPosition cameraPosition;
@@ -241,7 +241,7 @@ public class MapboxMapOptions implements Parcelable {
R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft,
- EIGHTY_NINE_DP * pxlRatio)),
+ NINETY_TWO_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop,
FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight,
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 ae4a8ee8d2..6d9df8aebd 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
@@ -27,6 +27,7 @@ import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -617,7 +618,7 @@ final class NativeMapView {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
@@ -882,12 +883,15 @@ final class NativeMapView {
fileSource.setApiBaseUrl(baseUrl);
}
- public float getPixelRatio() {
- return pixelRatio;
+ public Light getLight() {
+ if (isDestroyedOn("getLight")) {
+ return null;
+ }
+ return nativeGetLight();
}
- public Context getContext() {
- return mapView.getContext();
+ public float getPixelRatio() {
+ return pixelRatio;
}
//
@@ -1117,6 +1121,8 @@ final class NativeMapView {
String[] layerIds,
Object[] filter);
+ private native Light nativeGetLight();
+
int getWidth() {
if (isDestroyedOn("")) {
return 0;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index 09213934ae..7dcd84de75 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -282,8 +282,10 @@ public final class TrackingSettings {
*/
void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition,
boolean isFromLocation) {
- resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
- isFromLocation);
+ if (currentCameraPosition.target != null) {
+ resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
+ isFromLocation);
+ }
}
Location getMyLocation() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 507bec270d..7f44e0de07 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
/**
* Resembles the current Map transformation.
@@ -33,13 +34,18 @@ final class Transform implements MapView.OnMapChangedListener {
private CameraPosition cameraPosition;
private MapboxMap.CancelableCallback cameraCancelableCallback;
+
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
- Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings) {
+ private CameraChangeDispatcher cameraChangeDispatcher;
+
+ Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.mapView = mapView;
this.markerViewManager = markerViewManager;
this.trackingSettings = trackingSettings;
this.myLocationView = trackingSettings.getMyLocationView();
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull MapboxMap mapboxMap, @NonNull MapboxMapOptions options) {
@@ -79,6 +85,7 @@ final class Transform implements MapView.OnMapChangedListener {
cameraCancelableCallback.onFinish();
cameraCancelableCallback = null;
}
+ cameraChangeDispatcher.onCameraIdle();
mapView.removeOnMapChangedListener(this);
}
}
@@ -89,10 +96,12 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
if (callback != null) {
callback.onFinish();
}
+ cameraChangeDispatcher.onCameraIdle();
}
}
@@ -103,6 +112,8 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -118,8 +129,9 @@ final class Transform implements MapView.OnMapChangedListener {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
-
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -134,7 +146,12 @@ final class Transform implements MapView.OnMapChangedListener {
@Nullable
CameraPosition invalidateCameraPosition() {
if (mapView != null) {
- cameraPosition = mapView.getCameraPosition();
+ CameraPosition cameraPosition = mapView.getCameraPosition();
+ if (this.cameraPosition != null && !this.cameraPosition.equals(cameraPosition)) {
+ cameraChangeDispatcher.onCameraMove();
+ }
+
+ this.cameraPosition = cameraPosition;
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
}
@@ -143,10 +160,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void cancelTransitions() {
+ // notify user about cancel
+ cameraChangeDispatcher.onCameraMoveCanceled();
+
+ // notify animateCamera and easeCamera about cancelling
if (cameraCancelableCallback != null) {
+ cameraChangeDispatcher.onCameraIdle();
cameraCancelableCallback.onCancel();
cameraCancelableCallback = null;
}
+
+ // cancel ongoing transitions
mapView.cancelTransitions();
}
@@ -156,6 +180,10 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.resetNorth();
}
+ //
+ // Camera change listener API
+ //
+
void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) {
this.onCameraChangeListener = listener;
}
@@ -171,9 +199,6 @@ final class Transform implements MapView.OnMapChangedListener {
}
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
- // Cancel any animation
- cancelTransitions();
-
CameraPosition cameraPosition = invalidateCameraPosition();
if (cameraPosition != null) {
int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1));
@@ -186,6 +211,15 @@ final class Transform implements MapView.OnMapChangedListener {
}
void setZoom(double zoom, @NonNull PointF focalPoint, long duration) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
mapView.setZoom(zoom, focalPoint, duration);
}
@@ -277,6 +311,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void moveBy(double offsetX, double offsetY, long duration) {
+ if (duration > 0) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
+ }
mapView.moveBy(offsetX, offsetY, duration);
}
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 1bcf8a70b9..5f7b6c571b 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
@@ -193,12 +193,16 @@ public final class UiSettings {
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
setLogoEnabled(options.getLogoEnabled());
setLogoGravity(options.getLogoGravity());
- int[] logoMargins = options.getLogoMargins();
+ setLogoMargins(resources, options.getLogoMargins());
+ }
+
+ private void setLogoMargins(Resources resources, int[] logoMargins) {
if (logoMargins != null) {
setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
} else {
- int twoDp = (int) resources.getDimension(R.dimen.mapbox_two_dp);
- setLogoMargins(twoDp, twoDp, twoDp, twoDp);
+ // user did not specify margins when programmatically creating a map
+ int fourDp = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ setLogoMargins(fourDp, fourDp, fourDp, fourDp);
}
}
@@ -223,15 +227,23 @@ public final class UiSettings {
private void initialiseAttribution(Context context, MapboxMapOptions options) {
setAttributionEnabled(options.getAttributionEnabled());
setAttributionGravity(options.getAttributionGravity());
- int[] attributionMargins = options.getAttributionMargins();
+ setAttributionMargins(context, options.getAttributionMargins());
+ int attributionTintColor = options.getAttributionTintColor();
+ setAttributionTintColor(attributionTintColor != -1
+ ? attributionTintColor : ColorUtils.getPrimaryColor(context));
+ }
+
+ private void setAttributionMargins(Context context, int[] attributionMargins) {
if (attributionMargins != null) {
setAttributionMargins(attributionMargins[0], attributionMargins[1],
attributionMargins[2], attributionMargins[3]);
+ } else {
+ // user did not specify margins when programmatically creating a map
+ Resources resources = context.getResources();
+ int margin = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ int leftMargin = (int) resources.getDimension(R.dimen.mapbox_ninety_two_dp);
+ setAttributionMargins(leftMargin, margin, margin, margin);
}
-
- int attributionTintColor = options.getAttributionTintColor();
- setAttributionTintColor(attributionTintColor != -1
- ? attributionTintColor : ColorUtils.getPrimaryColor(context));
}
private void saveAttribution(Bundle outState) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index db2a335453..f5ef46a5d3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -440,6 +440,7 @@ public class MyLocationView extends View {
} else {
// Disable location and user dot
location = null;
+ locationSource.removeLocationUpdates();
locationSource.removeLocationEngineListener(userLocationListener);
locationSource.deactivate();
}
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 50ae6716e6..ce498da8f5 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
@@ -47,7 +47,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing a list of all
- * {@link OfflineRegion} in the database, or an error message otherwise.
+ * OfflineRegion in the database or an error message otherwise.
*/
public interface ListOfflineRegionsCallback {
/**
@@ -67,7 +67,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing the newly created
- * {@link OfflineRegion} in the database, or an error message otherwise.
+ * OfflineRegion in the database or an error message otherwise.
*/
public interface CreateOfflineRegionCallback {
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index 5ed6579e1c..fae53c2086 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -4,6 +4,7 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.storage.FileSource;
@@ -37,6 +38,9 @@ public class OfflineRegion {
//Region id
private long id;
+ // delete status
+ private boolean isDeleted;
+
private OfflineRegionDefinition definition;
/**
@@ -95,7 +99,7 @@ public class OfflineRegion {
}
/**
- * This callback receives an asynchronous response containing the {@link OfflineRegionStatus}
+ * This callback receives an asynchronous response containing the OfflineRegionStatus
* of the offline region, or a {@link String} error message otherwise.
*/
public interface OfflineRegionStatusCallback {
@@ -248,7 +252,7 @@ public class OfflineRegion {
*
* @param observer the observer to be notified
*/
- public void setObserver(@NonNull final OfflineRegionObserver observer) {
+ public void setObserver(@Nullable final OfflineRegionObserver observer) {
setOfflineRegionObserver(new OfflineRegionObserver() {
@Override
public void onStatusChanged(final OfflineRegionStatus status) {
@@ -256,7 +260,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.onStatusChanged(status);
+ if (observer != null) {
+ observer.onStatusChanged(status);
+ }
}
});
}
@@ -268,7 +274,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.onError(error);
+ if (observer != null) {
+ observer.onError(error);
+ }
}
});
}
@@ -280,7 +288,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.mapboxTileCountLimitExceeded(limit);
+ if (observer != null) {
+ observer.mapboxTileCountLimitExceeded(limit);
+ }
}
});
}
@@ -347,28 +357,31 @@ public class OfflineRegion {
* @param callback the callback to be invoked
*/
public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
- deleteOfflineRegion(new OfflineRegionDeleteCallback() {
- @Override
- public void onDelete() {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- callback.onDelete();
- OfflineRegion.this.finalize();
- }
- });
- }
+ if (!isDeleted) {
+ deleteOfflineRegion(new OfflineRegionDeleteCallback() {
+ @Override
+ public void onDelete() {
+ isDeleted = true;
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onDelete();
+ OfflineRegion.this.finalize();
+ }
+ });
+ }
- @Override
- public void onError(final String error) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- callback.onError(error);
- }
- });
- }
- });
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
index af98a46a9b..eae83e8c1f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
@@ -5,9 +5,15 @@ import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+/**
+ * Resource provides access to resource types.
+ */
public final class Resource {
// Note: Keep this in sync with include/mbgl/storage/resource.hpp
+ /**
+ * Resource type variants.
+ */
@IntDef( {UNKNOWN, STYLE, SOURCE, TILE, GLYPHS, SPRITE_IMAGE, SPRITE_JSON})
@Retention(RetentionPolicy.SOURCE)
public @interface Kind {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
index 8ded7ecd34..15e4474105 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
@@ -13,7 +13,7 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import java.util.Map;
/**
- * Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s.
+ * Composite functions combine Camera and SourceFunctions.
* <p>
* Composite functions allow the appearance of a map feature to change with both its
* properties and zoom. Each stop is an array with two elements, the first is an object
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
index 643a126388..4dbb461e4c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
@@ -11,7 +11,7 @@ import java.util.Collections;
public class Filter {
/**
- * Base {@link Filter} statement. Subclassed to provide concrete statements.
+ * Base Filter statement. Subclassed to provide concrete statements.
*/
public abstract static class Statement {
protected final String operator;
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 48e0ec5de3..5e345268f9 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
@@ -467,6 +467,27 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface FILL_EXTRUSION_TRANSLATE_ANCHOR {}
+ // ANCHOR: Whether extruded geometries are lit relative to the map or viewport.
+
+ /**
+ * The position of the light source is aligned to the rotation of the map.
+ */
+ public static final String ANCHOR_MAP = "map";
+ /**
+ * The position of the light source is aligned to the rotation of the viewport.
+ */
+ public static final String ANCHOR_VIEWPORT = "viewport";
+
+ /**
+ * Whether extruded geometries are lit relative to the map or viewport.
+ */
+ @StringDef({
+ ANCHOR_MAP,
+ ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ANCHOR {}
+
private Property() {
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
index a46c11b35c..6e6e4ca613 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
@@ -1,23 +1,51 @@
package com.mapbox.mapboxsdk.style.layers;
+/**
+ * Resembles transition property from the style specification.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#transition">Transition documentation</a>
+ */
public class TransitionOptions {
private long duration;
private long delay;
+ /**
+ * Create a transition property based on duration and a delay.
+ *
+ * @param duration the duration of the transition
+ * @param delay the delay to start the transition
+ */
public TransitionOptions(long duration, long delay) {
this.duration = duration;
this.delay = delay;
}
+ /**
+ * Create a transition property based on duration and a delay.
+ *
+ * @param duration the duration of the transition
+ * @param delay the delay to start the transition
+ * @return a new transition property object
+ */
public static TransitionOptions fromTransitionOptions(long duration, long delay) {
return new TransitionOptions(duration, delay);
}
+ /**
+ * Get the transition duration.
+ *
+ * @return the transition duration
+ */
public long getDuration() {
return duration;
}
+ /**
+ * Get the transition delay.
+ *
+ * @return the transition delay
+ */
public long getDelay() {
return delay;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
new file mode 100644
index 0000000000..b66a50b8a4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
@@ -0,0 +1,181 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.style.light;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
+/**
+ * The global light source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ */
+@UiThread
+public class Light {
+
+ private long nativePtr;
+
+ /**
+ * Creates a Light.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public Light(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+
+ /**
+ * Set the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
+ *
+ * @param anchor as String
+ */
+ public void setAnchor(@Property.ANCHOR String anchor) {
+ nativeSetAnchor(anchor);
+ }
+
+ /**
+ * Get the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
+ *
+ * @return anchor as String
+ */
+ @Property.ANCHOR public String getAnchor() {
+ return nativeGetAnchor();
+ }
+
+ /**
+ * Set the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
+ *
+ * @param position of the light
+ */
+ public void setPosition(@NonNull Position position) {
+ nativeSetPosition(position);
+ }
+
+ /**
+ * Get the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
+ *
+ * @return position as Position
+ */
+ public Position getPosition() {
+ return nativeGetPosition();
+ }
+
+ /**
+ * Get the Position property transition options.
+ *
+ * @return transition options for position
+ */
+ public TransitionOptions getPositionTransition() {
+ return nativeGetPositionTransition();
+ }
+
+ /**
+ * Set the Position property transition options.
+ *
+ * @param options transition options for position
+ */
+ public void setPositionTransition(TransitionOptions options) {
+ nativeSetPositionTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Set the Color property. Color tint for lighting extruded geometries.
+ *
+ * @param color as int
+ */
+ public void setColor(@ColorInt int color) {
+ nativeSetColor(PropertyFactory.colorToRgbaString(color));
+ }
+
+ /**
+ * Set the Color property. Color tint for lighting extruded geometries.
+ *
+ * @param color as String
+ */
+ public void setColor(String color) {
+ nativeSetColor(color);
+ }
+
+ /**
+ * Get the Color property. Color tint for lighting extruded geometries.
+ *
+ * @return color as String
+ */
+ public String getColor() {
+ return nativeGetColor();
+ }
+
+ /**
+ * Get the Color property transition options.
+ *
+ * @return transition options for color
+ */
+ public TransitionOptions getColorTransition() {
+ return nativeGetColorTransition();
+ }
+
+ /**
+ * Set the Color property transition options.
+ *
+ * @param options transition options for color
+ */
+ public void setColorTransition(TransitionOptions options) {
+ nativeSetColorTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Set the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+ *
+ * @param intensity as Float
+ */
+ public void setIntensity(float intensity) {
+ nativeSetIntensity(intensity);
+ }
+
+ /**
+ * Get the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+ *
+ * @return intensity as Float
+ */
+ public float getIntensity() {
+ return nativeGetIntensity();
+ }
+
+ /**
+ * Get the Intensity property transition options.
+ *
+ * @return transition options for intensity
+ */
+ public TransitionOptions getIntensityTransition() {
+ return nativeGetIntensityTransition();
+ }
+
+ /**
+ * Set the Intensity property transition options.
+ *
+ * @param options transition options for intensity
+ */
+ public void setIntensityTransition(TransitionOptions options) {
+ nativeSetIntensityTransition(options.getDuration(), options.getDelay());
+ }
+
+ private native void nativeSetAnchor(String anchor);
+ private native String nativeGetAnchor();
+ private native void nativeSetPosition(Position position);
+ private native Position nativeGetPosition();
+ private native TransitionOptions nativeGetPositionTransition();
+ private native void nativeSetPositionTransition(long duration, long delay);
+ private native void nativeSetColor(String color);
+ private native String nativeGetColor();
+ private native TransitionOptions nativeGetColorTransition();
+ private native void nativeSetColorTransition(long duration, long delay);
+ private native void nativeSetIntensity(float intensity);
+ private native float nativeGetIntensity();
+ private native TransitionOptions nativeGetIntensityTransition();
+ private native void nativeSetIntensityTransition(long duration, long delay);
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
new file mode 100644
index 0000000000..215db03ad2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
@@ -0,0 +1,81 @@
+package com.mapbox.mapboxsdk.style.light;
+
+/**
+ * Position of the light source relative to lit (extruded) geometries.
+ * <p>
+ * The position is constructed out of a radial coordinate, an azimuthal angle and a polar angle.
+ * where the radial coordinate indicates the distance from the center of the base of an object to its light, the
+ * azimuthal angle indicates the position of the light relative to 0° (0° when
+ * {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to viewport corresponds to the top of the
+ * viewport, or 0° when {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to map corresponds to due
+ * north, and degrees proceed clockwise), and polar indicates the height of the light
+ * (from 0°, directly above, to 180°, directly below).
+ */
+public class Position {
+
+ private float radialCoordinate;
+ private float azimuthalAngle;
+ private float polarAngle;
+
+ /**
+ * Creates a Position from a radial coordinate, an azimuthal angle & a polar angle.
+ *
+ * @param radialCoordinate the distance from the center of the base of an object to its light
+ * @param azimuthalAngle the position of the light relative to 0°
+ * @param polarAngle the height of the light
+ */
+ public Position(float radialCoordinate, float azimuthalAngle, float polarAngle) {
+ this.radialCoordinate = radialCoordinate;
+ this.azimuthalAngle = azimuthalAngle;
+ this.polarAngle = polarAngle;
+ }
+
+ /**
+ * Returns a Position from a radial coordinate, an azimuthal angle & a polar angle
+ *
+ * @param radialCoordinate the radial coordinate
+ * @param azimuthalAngle the azimuthal angle
+ * @param polarAngle the polar angle
+ * @return the created Position object
+ */
+ public static Position fromPosition(float radialCoordinate, float azimuthalAngle, float polarAngle) {
+ return new Position(radialCoordinate, azimuthalAngle, polarAngle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Position position = (Position) o;
+
+ if (Float.compare(position.radialCoordinate, radialCoordinate) != 0) {
+ return false;
+ }
+ if (Float.compare(position.azimuthalAngle, azimuthalAngle) != 0) {
+ return false;
+ }
+ return Float.compare(position.polarAngle, polarAngle) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (radialCoordinate != +0.0f ? Float.floatToIntBits(radialCoordinate) : 0);
+ result = 31 * result + (azimuthalAngle != +0.0f ? Float.floatToIntBits(azimuthalAngle) : 0);
+ result = 31 * result + (polarAngle != +0.0f ? Float.floatToIntBits(polarAngle) : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Position{"
+ + "radialCoordinate=" + radialCoordinate
+ + ", azimuthalAngle=" + azimuthalAngle
+ + ", polarAngle=" + polarAngle
+ + '}';
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
new file mode 100644
index 0000000000..067efe1092
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
@@ -0,0 +1,121 @@
+<%
+ const properties = locals.properties;
+ const doc = locals.doc;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.style.light;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
+/**
+ * The global light source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ */
+@UiThread
+public class Light {
+
+ private long nativePtr;
+
+ /**
+ * Creates a Light.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public Light(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+<% for (const property of properties) { -%>
+<% if (property.name == "position") {-%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param position of the light
+ */
+ public void set<%- camelize(property.name) %>(@NonNull Position position) {
+ nativeSet<%- camelize(property.name) %>(position);
+ }
+
+ /**
+ * Get the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @return <%- property.name %> as Position
+ */
+ public Position get<%- camelize(property.name) %>() {
+ return nativeGet<%- camelize(property.name) %>();
+ }
+<% } else { -%>
+<% if (property.name == "color") {-%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param <%- property.name %> as int
+ */
+ public void set<%- camelize(property.name) %>(@ColorInt int <%- property.name %>) {
+ nativeSet<%- camelize(property.name) %>(PropertyFactory.colorToRgbaString(<%- property.name %>));
+ }
+<% } -%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param <%- property.name %> as <%- propertyType(property) %>
+ */
+ public void set<%- camelize(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyJavaType(property) %> <%- property.name %>) {
+ nativeSet<%- camelize(property.name) %>(<%- property.name %>);
+ }
+
+ /**
+ * Get the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @return <%- property.name %> as <%- propertyType(property) %>
+ */
+ <%- propertyTypeAnnotation(property) %> public <%- propertyJavaType(property) %> get<%- camelize(property.name) %>() {
+ return nativeGet<%- camelize(property.name) %>();
+ }
+<% } -%>
+<% if (property.transition) { -%>
+
+ /**
+ * Get the <%- camelize(property.name) %> property transition options.
+ *
+ * @return transition options for <%- property.name %>
+ */
+ public TransitionOptions get<%- camelize(property.name) %>Transition() {
+ return nativeGet<%- camelize(property.name) %>Transition();
+ }
+
+ /**
+ * Set the <%- camelize(property.name) %> property transition options.
+ *
+ * @param options transition options for <%- property.name %>
+ */
+ public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
+ nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
+ }
+<% } -%>
+<% } -%>
+
+<% for (const property of properties) { -%>
+<% if (property.name == "position") {-%>
+ private native void nativeSet<%- camelize(property.name) %>(Position position);
+ private native Position nativeGet<%- camelize(property.name) %>();
+<% } else { -%>
+ private native void nativeSet<%- camelize(property.name) %>(<%- propertyJavaType(property) -%> <%- property.name %>);
+ private native <%- propertyJavaType(property) -%> nativeGet<%- camelize(property.name) %>();
+<% } -%>
+<% if (property.transition) { -%>
+ private native TransitionOptions nativeGet<%- camelize(property.name) %>Transition();
+ private native void nativeSet<%- camelize(property.name) %>Transition(long duration, long delay);
+<% } -%>
+<% } -%>
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java
new file mode 100644
index 0000000000..a613bf9587
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the Mapbox Maps Android Style Light API classes.
+ */
+package com.mapbox.mapboxsdk.style.light;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
index 7694604d9f..34c52c829b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
@@ -10,13 +10,31 @@ import android.support.annotation.Nullable;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.view.View;
+/**
+ * Animator utility class.
+ */
public class AnimatorUtils {
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param listener the animator end listener
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes,
@Nullable OnAnimationEndListener listener) {
animate(view, animatorRes, -1, listener);
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param duration the duration of the animator
+ * @param listener the animator end listener
+ */
public static void animate(final View view, @AnimatorRes int animatorRes, int duration,
@Nullable final OnAnimationEndListener listener) {
if (view == null) {
@@ -43,14 +61,33 @@ public class AnimatorUtils {
animator.start();
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes) {
animate(view, animatorRes, -1);
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param duration the duration of the animator
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes, int duration) {
animate(view, animatorRes, duration, null);
}
+ /**
+ * Animate a view rotation property to a value.
+ *
+ * @param view the view to be rotated
+ * @param rotation the value to animate to
+ */
public static void rotate(@NonNull final View view, float rotation) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(view, View.ROTATION, view.getRotation(), rotation);
@@ -64,6 +101,12 @@ public class AnimatorUtils {
rotateAnimator.start();
}
+ /**
+ * Animate a view rotation property by a value.
+ *
+ * @param view the view to be rotated
+ * @param rotationBy the value to animate by
+ */
public static void rotateBy(@NonNull final View view, float rotationBy) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
view.animate().rotationBy(rotationBy).setInterpolator(new FastOutSlowInInterpolator()).setListener(
@@ -76,6 +119,13 @@ public class AnimatorUtils {
});
}
+ /**
+ * Animate a view alpha property to a value.
+ *
+ * @param convertView the view to be animated
+ * @param alpha the value to animate to
+ * @param listener the animator end listener
+ */
public static void alpha(@NonNull final View convertView, float alpha,
@Nullable final OnAnimationEndListener listener) {
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -99,10 +149,19 @@ public class AnimatorUtils {
rotateAnimator.start();
}
+ /**
+ * Animate a view alpha property to a value.
+ *
+ * @param convertView the view to be animated
+ * @param alpha the value to animate to
+ */
public static void alpha(@NonNull final View convertView, float alpha) {
alpha(convertView, alpha, null);
}
+ /**
+ * An interface definition that is invoked when an animation ends.
+ */
public interface OnAnimationEndListener {
void onAnimationEnd();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index 2da2472d69..24c76243d9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -17,6 +17,9 @@ import com.mapbox.mapboxsdk.exceptions.ConversionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+/**
+ * Color utility class.
+ */
public class ColorUtils {
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index ce20cb9a8b..8edbd47c29 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -13,6 +13,6 @@
<dimen name="mapbox_eight_dp">8dp</dimen>
<dimen name="mapbox_ten_dp">10dp</dimen>
<dimen name="mapbox_sixteen_dp">16dp</dimen>
- <dimen name="mapbox_ninety_five_dp">95dp</dimen>
+ <dimen name="mapbox_ninety_two_dp">92dp</dimen>
<dimen name="mapbox_my_locationview_outer_circle">18dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
index 5f6f6b6c6d..1c259af2d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
@@ -9,6 +9,7 @@ import org.mockito.MockitoAnnotations;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
+import static org.mockito.Mockito.when;
public class IconTest {
@@ -18,6 +19,7 @@ public class IconTest {
@Before
public void beforeTest() {
MockitoAnnotations.initMocks(this);
+ when(bitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 7c263652af..656789fcdb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -57,10 +57,7 @@ dependencies {
}
// Support libraries
- compile rootProject.ext.dep.supportAnnotations
- compile rootProject.ext.dep.supportV4
compile rootProject.ext.dep.supportAppcompatV7
- compile rootProject.ext.dep.supportDesign
compile rootProject.ext.dep.supportRecyclerView
// Leak Canary
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
index 5d944b5dd4..f8243ca44f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
@@ -4,5 +4,6 @@
-dontwarn org.codehaus.**
-keep class com.google.**
-dontwarn com.google.**
+-dontwarn java.nio.**
-keep class com.mapbox.mapboxsdk.testapp.model.customlayer.ExampleCustomLayer { *; }
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java
new file mode 100644
index 0000000000..36833fb4ee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java
@@ -0,0 +1,162 @@
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+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.light.Light;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.style.light.Position;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.FillExtrusionStyleTestActivity;
+
+import timber.log.Timber;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+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;
+import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
+import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+@RunWith(AndroidJUnit4.class)
+public class LightTest extends BaseActivityTest {
+
+ private Light light;
+
+ @Test
+ public void testAnchor() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("anchor");
+ assertNotNull(light);
+ // Set and Get
+ light.setAnchor(ANCHOR_MAP);
+ assertEquals("Anchor should match", ANCHOR_MAP, light.getAnchor());
+ }
+
+ @Test
+ public void testPositionTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("positionTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setPositionTransition(options);
+ assertEquals("Transition options should match", options, light.getPositionTransition());
+ }
+
+ @Test
+ public void testPosition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("position");
+ assertNotNull(light);
+
+ // Set and Get
+ Position position = new Position(1,2,3);
+ light.setPosition(position);
+ assertEquals("Position should match", position, light.getPosition());
+ }
+
+ @Test
+ public void testColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("colorTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setColorTransition(options);
+ assertEquals("Transition options should match", options, light.getColorTransition());
+ }
+
+ @Test
+ public void testColor() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("color");
+ assertNotNull(light);
+ // Set and Get
+ light.setColor("rgba(0, 0, 0, 1)");
+ assertEquals("Color should match", "rgba(0, 0, 0, 1)".replaceAll("\\s+",""), light.getColor());
+ }
+
+ @Test
+ public void testIntensityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("intensityTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setIntensityTransition(options);
+ assertEquals("Transition options should match", options, light.getIntensityTransition());
+ }
+
+ @Test
+ public void testIntensity() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("intensity");
+ assertNotNull(light);
+ // Set and Get
+ light.setIntensity(0.3f);
+ assertEquals("Intensity should match", 0.3f, light.getIntensity());
+ }
+
+ private void setupLayer() {
+ onView(withId(R.id.mapView)).perform(new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ light = mapboxMap.getLight();
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.6f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+ });
+ }
+
+ @Override
+ protected Class getActivityClass() {
+ return FillExtrusionStyleTestActivity.class;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs
new file mode 100644
index 0000000000..cb3ba58100
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs
@@ -0,0 +1,128 @@
+<%
+ const properties = locals.properties;
+-%>
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+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.light.Light;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.style.light.Position;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.FillExtrusionStyleTestActivity;
+
+import timber.log.Timber;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+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;
+import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
+import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+@RunWith(AndroidJUnit4.class)
+public class LightTest extends BaseActivityTest {
+
+ private Light light;
+<% for (const property of properties) { -%>
+<% if (property.transition) { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>Transition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>TransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.set<%- camelize(property.name) %>Transition(options);
+ assertEquals("Transition options should match", options, light.get<%- camelize(property.name) %>Transition());
+ }
+<% } -%>
+<% if (property.name == "position") { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>");
+ assertNotNull(light);
+
+ // Set and Get
+ Position position = new Position(1,2,3);
+ light.set<%- camelize(property.name) %>(position);
+ assertEquals("Position should match", position, light.get<%- camelize(property.name) %>());
+ }
+<% } else { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>");
+ assertNotNull(light);
+ // Set and Get
+ light.set<%- camelize(property.name) %>(<%- defaultValueJava(property) %>);
+<% if (property.name == 'color') { -%>
+ assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>.replaceAll("\\s+",""), light.get<%- camelize(property.name) %>());
+<% } else { -%>
+ assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>, light.get<%- camelize(property.name) %>());
+<% } -%>
+ }
+<% } -%>
+<% } -%>
+
+ private void setupLayer() {
+ onView(withId(R.id.mapView)).perform(new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ light = mapboxMap.getLight();
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.6f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+ });
+ }
+
+ @Override
+ protected Class getActivityClass() {
+ return FillExtrusionStyleTestActivity.class;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 9ede763533..1a70e4548a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -661,7 +661,9 @@
<activity
android:name=".activity.espresso.EspressoTestActivity"
android:screenOrientation="portrait"/>
-
+ <activity
+ android:name=".activity.style.FillExtrusionStyleTestActivity"
+ android:screenOrientation="portrait"/>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
index 08399f3b3e..60518239c8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
@@ -43,10 +43,35 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
- mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
+ mapboxMap.setOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() {
@Override
- public void onCameraChange(CameraPosition position) {
- Timber.w("OnCameraChange: " + position);
+ public void onCameraIdle() {
+ Timber.e("OnCameraIdle");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveCancelListener(new MapboxMap.OnCameraMoveCanceledListener() {
+ @Override
+ public void onCameraMoveCanceled() {
+ Timber.e("OnCameraMoveCanceled");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() {
+ @Override
+ public void onCameraMove() {
+ Timber.e("OnCameraMove");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveStartedistener(new MapboxMap.OnCameraMoveStartedListener() {
+
+ private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"};
+
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ // reason ranges from 1 <-> 3
+ Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]);
}
});
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
index be5d809457..344e9e140a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
@@ -274,22 +274,20 @@ public class OfflineActivity extends AppCompatActivity
}
// Debug
- Timber.d(String.format("%s/%s resources; %s bytes downloaded.",
+ Timber.d("%s/%s resources; %s bytes downloaded.",
String.valueOf(status.getCompletedResourceCount()),
String.valueOf(status.getRequiredResourceCount()),
- String.valueOf(status.getCompletedResourceSize())));
+ String.valueOf(status.getCompletedResourceSize()));
}
@Override
public void onError(OfflineRegionError error) {
- Timber.e("onError reason: " + error.getReason());
- Timber.e("onError message: " + error.getMessage());
- offlineRegion.setObserver(null);
+ Timber.e("onError: %s, %s", error.getReason(), error.getMessage());
}
@Override
public void mapboxTileCountLimitExceeded(long limit) {
- Timber.e("Mapbox tile count limit exceeded: " + limit);
+ Timber.e("Mapbox tile count limit exceeded: %s", limit);
}
});
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
index f444aa40f0..def7d1678a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
@@ -4,6 +4,9 @@ import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -11,6 +14,10 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.style.functions.Function;
import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.light.Light;
+import com.mapbox.mapboxsdk.style.light.Position;
import com.mapbox.mapboxsdk.testapp.R;
import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
@@ -25,6 +32,13 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpa
public class BuildingFillExtrusionActivity extends AppCompatActivity {
private MapView mapView;
+ private MapboxMap mapboxMap;
+ private Light light;
+
+ private boolean isMapAnchorLight;
+ private boolean isLowIntensityLight;
+ private boolean isRedColor;
+ private boolean isInitPosition;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -35,21 +49,72 @@ public class BuildingFillExtrusionActivity extends AppCompatActivity {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap map) {
- FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
- fillExtrusionLayer.setSourceLayer("building");
- fillExtrusionLayer.setFilter(eq("extrude", "true"));
- fillExtrusionLayer.setMinZoom(15);
- fillExtrusionLayer.setProperties(
- fillExtrusionColor(Color.LTGRAY),
- fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
- fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
- fillExtrusionOpacity(0.6f)
- );
- map.addLayer(fillExtrusionLayer);
+ mapboxMap = map;
+ setupBuildings();
+ setupLight();
}
});
}
+ private void setupBuildings() {
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.9f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+
+ private void setupLight() {
+ light = mapboxMap.getLight();
+
+ findViewById(R.id.fabLightPosition).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ isInitPosition = !isInitPosition;
+ if (isInitPosition) {
+ light.setPosition(new Position(1.5f, 90, 80));
+ } else {
+ light.setPosition(new Position(1.15f, 210, 30));
+ }
+ }
+ });
+
+ findViewById(R.id.fabLightColor).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ isRedColor = !isRedColor;
+ light.setColor(PropertyFactory.colorToRgbaString(isRedColor ? Color.RED : Color.BLUE));
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_building, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (light != null) {
+ int id = item.getItemId();
+ if (id == R.id.menu_action_anchor) {
+ isMapAnchorLight = !isMapAnchorLight;
+ light.setAnchor(isMapAnchorLight ? Property.ANCHOR_MAP : Property.ANCHOR_VIEWPORT);
+ } else if (id == R.id.menu_action_intensity) {
+ isLowIntensityLight = !isLowIntensityLight;
+ light.setIntensity(isLowIntensityLight ? 0.35f : 1.0f);
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
@Override
protected void onStart() {
super.onStart();
@@ -91,5 +156,4 @@ public class BuildingFillExtrusionActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java
new file mode 100644
index 0000000000..1ff0b0e8e1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java
@@ -0,0 +1,78 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+
+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.testapp.R;
+
+public class FillExtrusionStyleTestActivity extends AppCompatActivity {
+
+ public MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_extrusion_test);
+
+ // Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ FillExtrusionStyleTestActivity.this.mapboxMap = mapboxMap;
+ }
+ });
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
index b87c723fda..b02b35b0d0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
@@ -63,7 +63,9 @@ public class MockLocationEngine extends LocationEngine {
@Override
public void removeLocationUpdates() {
- handler.removeCallbacksAndMessages(null);
+ if (handler != null) {
+ handler.removeCallbacksAndMessages(null);
+ }
}
private Location getNextLocation() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml
new file mode 100644
index 0000000000..f9e55e1480
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18,4V3c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1V6h1v4H9v11c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-9h8V4h-3z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
index d9a10871b5..fa37c485d7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<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"
- android:orientation="vertical">
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
@@ -13,6 +12,27 @@
app:mapbox_cameraTargetLng="-74.0066"
app:mapbox_cameraTilt="45"
app:mapbox_cameraZoom="15"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+ app:mapbox_styleUrl="@string/mapbox_style_dark"/>
-</RelativeLayout>
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLightPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_marginBottom="82dp"
+ android:layout_marginRight="@dimen/fab_margin"
+ android:layout_marginEnd="@dimen/fab_margin"
+ android:src="@drawable/ic_my_location"
+ app:backgroundTint="@color/accent"
+ app:layout_anchorGravity="top"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLightColor"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_paint"
+ app:backgroundTint="@color/primary"/>
+
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml
new file mode 100644
index 0000000000..d9a10871b5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml
@@ -0,0 +1,18 @@
+<?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">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:mapbox_cameraTargetLat="40.7135"
+ app:mapbox_cameraTargetLng="-74.0066"
+ app:mapbox_cameraTilt="45"
+ app:mapbox_cameraZoom="15"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
index 9932803907..c2098b0f5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
@@ -16,6 +16,6 @@
app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
app:mapbox_uiAttributionGravity="top|end"
app:mapbox_uiLogoGravity="top|end"
- app:mapbox_uiLogoMarginRight="10dp"/>
+ app:mapbox_uiLogoMarginRight="28dp"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml
new file mode 100644
index 0000000000..92d1dd5380
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/menu_action_intensity"
+ android:title="Change intensity"
+ app:showAsAction="never"/>
+ <item
+ android:id="@+id/menu_action_anchor"
+ android:title="Change Anchor"
+ app:showAsAction="never"/>
+</menu>
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 120c0219e4..bc90896812 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -12,6 +12,7 @@ buildscript {
allprojects {
repositories {
jcenter()
+ maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
}
}
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index c111744ed0..84591d644b 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -168,6 +168,10 @@ add_library(mbgl-android STATIC
platform/android/src/style/functions/identity_stops.hpp
platform/android/src/style/functions/interval_stops.cpp
platform/android/src/style/functions/interval_stops.hpp
+ platform/android/src/style/position.cpp
+ platform/android/src/style/position.hpp
+ platform/android/src/style/light.cpp
+ platform/android/src/style/light.hpp
# FileSource holder
platform/android/src/file_source.cpp
diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle
index 738f571c09..5e80e344e4 100644
--- a/platform/android/dependencies.gradle
+++ b/platform/android/dependencies.gradle
@@ -7,21 +7,21 @@ ext {
versionCode = 11
versionName = "5.0.0"
+ mapboxServicesVersion = "2.1.1"
supportLibVersion = "25.3.1"
- leakCanaryVersion = '1.5'
wearableVersion = '2.0.0'
-
espressoVersion = '2.2.2'
testRunnerVersion = '0.5'
+ leakCanaryVersion = '1.5'
dep = [
// mapbox
- mapboxJavaServices : 'com.mapbox.mapboxsdk:mapbox-java-services:2.1.0@jar',
- mapboxJavaGeoJSON : 'com.mapbox.mapboxsdk:mapbox-java-geojson:2.1.0@jar',
- mapboxAndroidTelemetry : 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.1.0@aar',
+ mapboxJavaServices : "com.mapbox.mapboxsdk:mapbox-java-services:${mapboxServicesVersion}@jar",
+ mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-java-geojson:${mapboxServicesVersion}@jar",
+ mapboxAndroidTelemetry : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${mapboxServicesVersion}@aar",
// mapzen lost
- lost : 'com.mapzen.android:lost:2.2.0',
+ lost : 'com.mapzen.android:lost:3.0.0',
// unit test
junit : 'junit:junit:4.12',
@@ -47,7 +47,7 @@ ext {
// square crew
timber : 'com.jakewharton.timber:timber:4.5.1',
- okhttp3 : 'com.squareup.okhttp3:okhttp:3.6.0',
+ okhttp3 : 'com.squareup.okhttp3:okhttp:3.7.0',
leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}",
leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}",
leakCanaryTest : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index c7ad166b13..1d35abd7b2 100644
--- a/platform/android/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip \ No newline at end of file
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 5d8fc4cc6d..bb04e3ba2a 100644
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -8,6 +8,13 @@ const _ = require('lodash');
require('../../../scripts/style-code');
// Specification parsing //
+const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => {
+ var property = spec[`light`][name];
+ property.name = name;
+ property['light-property'] = true;
+ memo.push(property);
+ return memo;
+}, []);
// Collect layer types from spec
var layers = Object.keys(spec.layer.type.values).map((type) => {
@@ -37,7 +44,7 @@ var layers = Object.keys(spec.layer.type.values).map((type) => {
// Process all layer properties
const layoutProperties = _(layers).map('layoutProperties').flatten().value();
const paintProperties = _(layers).map('paintProperties').flatten().value();
-const allProperties = _(layoutProperties).union(paintProperties).value();
+const allProperties = _(layoutProperties).union(paintProperties).union(lightProperties).value();
const enumProperties = _(allProperties).filter({'type': 'enum'}).value();
global.propertyType = function propertyType(property) {
@@ -59,12 +66,31 @@ global.propertyType = function propertyType(property) {
}
}
+global.propertyJavaType = function propertyType(property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'boolean';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'String';
+ case 'enum':
+ return 'String';
+ case 'color':
+ return 'String';
+ case 'array':
+ return `${propertyJavaType({type:property.value})}[]`;
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+ }
+
global.propertyJNIType = function propertyJNIType(property) {
switch (property.type) {
case 'boolean':
return 'jboolean';
- case 'jfloat':
- return 'Float';
+ case 'number':
+ return 'jfloat';
case 'String':
return 'String';
case 'enum':
@@ -93,6 +119,9 @@ global.propertyNativeType = function (property) {
case 'string':
return 'std::string';
case 'enum':
+ if(property['light-property']){
+ return `Light${camelize(property.name)}Type`;
+ }
return `${camelize(property.name)}Type`;
case 'color':
return `Color`;
@@ -215,6 +244,53 @@ global.propertyValueDoc = function (property, value) {
return doc;
};
+global.isDataDriven = function (property) {
+ return property['property-function'] === true;
+};
+
+global.isLightProperty = function (property) {
+ return property['light-property'] === true;
+};
+
+global.propertyValueType = function (property) {
+ if (isDataDriven(property)) {
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ } else {
+ return `PropertyValue<${evaluatedType(property)}>`;
+ }
+};
+
+global.evaluatedType = function (property) {
+ if (/-translate-anchor$/.test(property.name)) {
+ return 'TranslateAnchorType';
+ }
+ if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
+ return 'AlignmentType';
+ }
+ if (/position/.test(property.name)) {
+ return 'Position';
+ }
+ switch (property.type) {
+ case 'boolean':
+ return 'bool';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'std::string';
+ case 'enum':
+ return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`;
+ case 'color':
+ return `Color`;
+ case 'array':
+ if (property.length) {
+ return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`;
+ } else {
+ return `std::vector<${evaluatedType({type: property.value})}>`;
+ }
+ default: throw new Error(`unknown type for ${property.name}`)
+ }
+};
+
global.supportsZoomFunction = function (property) {
return property['zoom-function'] === true;
};
@@ -225,6 +301,16 @@ global.supportsPropertyFunction = function (property) {
// Template processing //
+// Java + JNI Light (Peer model)
+const lightHpp = ejs.compile(fs.readFileSync('platform/android/src/style/light.hpp.ejs', 'utf8'), {strict: true});;
+const lightCpp = ejs.compile(fs.readFileSync('platform/android/src/style/light.cpp.ejs', 'utf8'), {strict: true});;
+const lightJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs', 'utf8'), {strict: true});
+const lightJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs', 'utf8'), {strict: true});
+writeIfModified(`platform/android/src/style/light.hpp`, lightHpp({properties: lightProperties}));
+writeIfModified(`platform/android/src/style/light.cpp`, lightCpp({properties: lightProperties}));
+writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties}));
+writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties}));
+
// Java + JNI Layers (Peer model)
const layerHpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true});
const layerCpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true});
@@ -238,7 +324,6 @@ for (const layer of layers) {
writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer));
}
-
// Java PropertyFactory
const propertiesTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true});
writeIfModified(
diff --git a/platform/android/scripts/release.py b/platform/android/scripts/release.py
index 8abcccffdb..ce554d1362 100644
--- a/platform/android/scripts/release.py
+++ b/platform/android/scripts/release.py
@@ -1,5 +1,5 @@
'''
-Utility to schedule SDK builds in Bitrise.
+Utility to schedule SDK builds on CircleCI.
Examples:
@@ -33,7 +33,7 @@ Examples:
TODO:
-- Add a flag to wait until the release has been built (Bitrise) and published (Maven).
+- Add a flag to wait until the release has been built (CircleCI) and published (Maven).
'''
@@ -49,8 +49,8 @@ ALLOWED_STAGES = ['snapshot', 'beta', 'final']
# Get the version from GRADLE_PROPERTIES_PATH below
CURRENT_VERSION_TAG = 'current'
-# You can find the API token in https://www.bitrise.io/app/79cdcbdc42de4303#/code -> API token
-BITRISE_API_TOKEN_ENV_VAR = 'BITRISE_API_TOKEN'
+# You can add your API token on https://circleci.com/account/api
+CIRCLECI_API_TOKEN_ENV_VAR = 'CIRCLECI_API_TOKEN'
# In the future we might want to consider alpha, or rc.
ALLOWED_PRE_RELEASE = ['beta']
@@ -62,8 +62,8 @@ GRADLE_TOKEN = 'VERSION_NAME='
FABRIC_PROPERTIES_PATH = '%s/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties' % MAPBOX_GL_ANDROID_SDK_PATH
FABRIC_TOKEN = 'fabric-version='
-# Bitrise
-URL_BITRISE = 'https://www.bitrise.io/app/79cdcbdc42de4303/build/start.json'
+# Triggers a new build, returns a summary of the build
+URL_CIRCLECI = 'https://circleci.com/api/v1.1/project/github/mapbox/mapbox-gl-native/tree/' # + :branch
# We support three parameters: stage, branch, and version
@click.command()
@@ -129,7 +129,7 @@ def publish_snapshot(branch, version):
if dirty_gradle:
git_add(path=GRADLE_PROPERTIES_PATH)
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
def publish_beta(branch, version):
click.echo('Publishing beta from branch: %s (version: %s).' % (branch, version))
@@ -137,7 +137,7 @@ def publish_beta(branch, version):
if dirty_gradle:
git_add(path=GRADLE_PROPERTIES_PATH)
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
def publish_final(branch, version):
click.echo('Publishing final release from branch: %s (version: %s).' % (branch, version))
@@ -149,7 +149,7 @@ def publish_final(branch, version):
git_add(path=FABRIC_PROPERTIES_PATH)
if dirty_gradle or dirty_fabric:
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
#
# Utils
@@ -166,26 +166,24 @@ def execute_call(command):
abort_with_message('Command failed: %s' % command)
#
-# Bitrise
+# CircleCI
#
-def get_bitrise_api_token():
- bitrise_api_token = os.environ.get(BITRISE_API_TOKEN_ENV_VAR)
- if not bitrise_api_token:
- abort_with_message('You need to set the BITRISE_API_TOKEN environment variable.')
- click.echo('Found Bitrise API token.')
- return bitrise_api_token
-
-def do_bitrise_request(build_params):
- data = {
- 'hook_info': {'type': 'bitrise', 'api_token': get_bitrise_api_token()},
- 'build_params' : build_params}
- click.echo('Bitrise request data: %s' % json.dumps(data))
+def get_circleci_api_token():
+ circleci_api_token = os.environ.get(CIRCLECI_API_TOKEN_ENV_VAR)
+ if not circleci_api_token:
+ abort_with_message('You need to set the CIRCLECI_API_TOKEN environment variable.')
+ click.echo('Found CircleCI API token.')
+ return circleci_api_token
+
+def do_circleci_request(branch):
+ url = URL_CIRCLECI + branch
+ params = {'circle-token': get_circleci_api_token()}
+ click.echo('CircleCI request to %s (params: %s)' % (url, json.dumps(params)))
click.confirm('\nDo you want to start a build?', abort=True)
- r = requests.post(URL_BITRISE, data=json.dumps(data))
- click.echo('- Bitrise response code: %s' % r.status_code)
- click.echo('- Bitrise response content: %s' % r.text)
+ r = requests.post(url, params=params)
+ click.echo('- CircleCI response code: %s' % r.status_code)
#
# Git
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 53691acb39..6c490fad5c 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -45,6 +45,7 @@
#include "style/functions/stop.hpp"
#include "style/layers/layers.hpp"
#include "style/sources/sources.hpp"
+#include "style/light.hpp"
namespace mbgl {
namespace android {
@@ -153,6 +154,8 @@ void registerNatives(JavaVM *vm) {
TransitionOptions::registerNative(env);
registerNativeLayers(env);
registerNativeSources(env);
+ Light::registerNative(env);
+ Position::registerNative(env);
Stop::registerNative(env);
CategoricalStops::registerNative(env);
ExponentialStops::registerNative(env);
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index aa5873b273..d6f2cb83e8 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -11,8 +11,9 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
auto center = options.center.value();
center.wrap();
- // convert bearing, core ranges from [−π rad, π rad], android from 0 to 360 degrees
- double bearing_degrees = options.angle.value_or(0) * 180.0 / M_PI;
+ // convert bearing, measured in radians counterclockwise from true north.
+ // Wrapped to [−π rad, π rad). Android binding from 0 to 360 degrees
+ double bearing_degrees = -options.angle.value_or(0) * util::RAD2DEG;
while (bearing_degrees > 360) {
bearing_degrees -= 360;
}
@@ -21,7 +22,7 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
}
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
- double tilt_degrees = options.pitch.value_or(0) * 180 / M_PI;
+ double tilt_degrees = options.pitch.value_or(0) * util::RAD2DEG;
return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
}
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 51ce9c031d..73a4f96549 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -46,6 +46,7 @@
#include "java/util.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
+#include "style/light.hpp"
namespace mbgl {
namespace android {
@@ -385,12 +386,12 @@ void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::
void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
mbgl::CameraOptions options;
if (angle != -1) {
- options.angle = (-angle * M_PI) / 180;
+ options.angle = -angle * util::DEG2RAD;
}
options.center = mbgl::LatLng(latitude, longitude);
options.padding = insets;
if (pitch != -1) {
- options.pitch = pitch * M_PI / 180;
+ options.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
options.zoom = zoom;
@@ -402,12 +403,12 @@ void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitu
void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180;
+ cameraOptions.angle = -angle * util::DEG2RAD;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
cameraOptions.padding = insets;
if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
+ cameraOptions.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
cameraOptions.zoom = zoom;
@@ -426,12 +427,12 @@ void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitu
void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180 ;
+ cameraOptions.angle = -angle * util::DEG2RAD;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
cameraOptions.padding = insets;
if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
+ cameraOptions.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
cameraOptions.zoom = zoom;
@@ -819,6 +820,15 @@ jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesFo
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) }));
}
+jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
+ mbgl::style::Light* light = map->getLight();
+ if (light) {
+ return jni::Object<Light>(Light::createJavaLightPeer(env, *map, *light));
+ } else {
+ return jni::Object<Light>();
+ }
+}
+
jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
// Get the core layers
@@ -1535,6 +1545,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
+ METHOD(&NativeMapView::getLight, "nativeGetLight"),
METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
METHOD(&NativeMapView::addLayer, "nativeAddLayer"),
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index e5fcb9badd..df43ad08b7 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -24,6 +24,7 @@
#include "style/sources/sources.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
+#include "style/light.hpp"
#include <exception>
#include <string>
@@ -230,6 +231,8 @@ public:
jni::jfloat, jni::Array<jni::String>,
jni::Array<jni::Object<>> jfilter);
+ jni::Object<Light> getLight(JNIEnv&);
+
jni::Array<jni::Object<Layer>> getLayers(JNIEnv&);
jni::Object<Layer> getLayer(JNIEnv&, jni::String);
diff --git a/platform/android/src/style/conversion/position.hpp b/platform/android/src/style/conversion/position.hpp
new file mode 100644
index 0000000000..f32a892c0c
--- /dev/null
+++ b/platform/android/src/style/conversion/position.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "../../conversion/conversion.hpp"
+
+#include <jni/jni.hpp>
+#include <mbgl/style/position.hpp>
+#include "../../jni/local_object.hpp"
+#include "../position.hpp"
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template<>
+struct Converter<jni::Object<Position>, mbgl::style::Position> {
+ Result<jni::Object<Position>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const {
+ std::array<float, 3> cartPosition = value.getSpherical();
+ return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]);
+ }
+};
+
+template<>
+struct Converter<mbgl::style::Position, jni::Object<Position>> {
+ Result<mbgl::style::Position> operator()(jni::JNIEnv &env, const jni::Object<Position> &value) const {
+ float radialCoordinate = Position::getRadialCoordinate(env, value);
+ float azimuthalAngle = Position::getAzimuthalAngle(env, value);
+ float polarAngle = Position::getPolarAngle(env, value);
+ std::array<float, 3> cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}};
+ mbgl::style::Position position{};
+ position.set(cartPosition);
+ return position;
+ }
+};
+
+}
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
index d9921e582e..a00f668c24 100644
--- a/platform/android/src/style/conversion/types.hpp
+++ b/platform/android/src/style/conversion/types.hpp
@@ -92,6 +92,13 @@ struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> {
}
};
+template <>
+struct Converter<jni::jobject*, mbgl::style::LightAnchorType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LightAnchorType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
} // namespace conversion
} // namespace android
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
index e3108fdf5b..e96de3b01e 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -206,6 +206,20 @@ namespace conversion {
}
}
+ // anchor
+ inline std::string toString(mbgl::style::LightAnchorType value) {
+ switch (value) {
+ case mbgl::style::LightAnchorType::Map:
+ return "map";
+ break;
+ case mbgl::style::LightAnchorType::Viewport:
+ return "viewport";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
} // namespace conversion
} // namespace android
diff --git a/platform/android/src/style/light.cpp b/platform/android/src/style/light.cpp
new file mode 100644
index 0000000000..71f1cb076e
--- /dev/null
+++ b/platform/android/src/style/light.cpp
@@ -0,0 +1,146 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#include <mbgl/map/map.hpp>
+#include "light.hpp"
+#include "conversion/transition_options.hpp"
+#include "conversion/position.hpp"
+
+namespace mbgl {
+namespace android {
+
+Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight)
+ : light(coreLight) , map(&coreMap) {
+}
+
+static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) {
+ return new Light(map, coreLight);
+}
+
+jni::jobject* Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) {
+ std::unique_ptr<Light> peerLight = std::unique_ptr<Light>(initializeLightPeer(map, coreLight));
+ jni::jobject* result = peerLight->createJavaPeer(env);
+ peerLight.release();
+ return result;
+}
+
+jni::Class<Light> Light::javaClass;
+
+jni::jobject* Light::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = Light::javaClass.template GetConstructor<jni::jlong>(env);
+ return Light::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+}
+
+void Light::setAnchor(jni::JNIEnv& env, jni::String property) {
+ std::string anchorStr = jni::Make<std::string>(env, property);
+ if (anchorStr.compare("map") == 0) {
+ light.setAnchor(LightAnchorType::Map);
+ } else if (anchorStr.compare("viewport") == 0) {
+ light.setAnchor(LightAnchorType::Viewport);
+ }
+}
+
+jni::String Light::getAnchor(jni::JNIEnv& env) {
+ auto anchorType = light.getAnchor();
+ if (anchorType == LightAnchorType::Map) {
+ return jni::Make<jni::String>(env, "map");
+ } else {
+ return jni::Make<jni::String>(env, "viewport");
+ }
+}
+
+void Light::setPosition(jni::JNIEnv& env, jni::Object<Position> jposition) {
+ using namespace mbgl::android::conversion;
+ auto position = *convert<mbgl::style::Position>(env, jposition);
+ light.setPosition(position);
+}
+
+jni::Object<Position> Light::getPosition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::Position position = light.getPosition().asConstant();
+ return *convert<jni::Object<Position>>(env, position);
+}
+
+jni::Object<TransitionOptions> Light::getPositionTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getPositionTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setPositionTransition(options);
+}
+
+void Light::setColor(jni::JNIEnv& env, jni::String property) {
+ auto color = Color::parse(jni::Make<std::string>(env, property));
+ if (color) {
+ light.setColor(color.value());
+ }
+}
+
+jni::String Light::getColor(jni::JNIEnv &env) {
+ auto color = light.getColor().asConstant();
+ return jni::Make<jni::String>(env, color.stringify());
+}
+
+jni::Object<TransitionOptions> Light::getColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setColorTransition(options);
+}
+
+void Light::setIntensity(jni::JNIEnv&, jni::jfloat property) {
+ light.setIntensity(property);
+}
+
+jni::jfloat Light::getIntensity(jni::JNIEnv&) {
+ return light.getIntensity().asConstant();
+}
+
+jni::Object<TransitionOptions> Light::getIntensityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getIntensityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setIntensityTransition(options);
+}
+
+void Light::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Light::javaClass = *jni::Class<Light>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+ // Register the peer
+ jni::RegisterNativePeer<Light>(env, Light::javaClass, "nativePtr",
+ METHOD(&Light::getAnchor, "nativeGetAnchor"),
+ METHOD(&Light::setAnchor, "nativeSetAnchor"),
+ METHOD(&Light::getPositionTransition, "nativeGetPositionTransition"),
+ METHOD(&Light::setPositionTransition, "nativeSetPositionTransition"),
+ METHOD(&Light::getPosition, "nativeGetPosition"),
+ METHOD(&Light::setPosition, "nativeSetPosition"),
+ METHOD(&Light::getColorTransition, "nativeGetColorTransition"),
+ METHOD(&Light::setColorTransition, "nativeSetColorTransition"),
+ METHOD(&Light::getColor, "nativeGetColor"),
+ METHOD(&Light::setColor, "nativeSetColor"),
+ METHOD(&Light::getIntensityTransition, "nativeGetIntensityTransition"),
+ METHOD(&Light::setIntensityTransition, "nativeSetIntensityTransition"),
+ METHOD(&Light::getIntensity, "nativeGetIntensity"),
+ METHOD(&Light::setIntensity, "nativeSetIntensity"));
+}
+
+} // namespace android
+} // namespace mb
diff --git a/platform/android/src/style/light.cpp.ejs b/platform/android/src/style/light.cpp.ejs
new file mode 100644
index 0000000000..17f0bba09d
--- /dev/null
+++ b/platform/android/src/style/light.cpp.ejs
@@ -0,0 +1,123 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#include <mbgl/map/map.hpp>
+#include "light.hpp"
+#include "conversion/transition_options.hpp"
+#include "conversion/position.hpp"
+
+namespace mbgl {
+namespace android {
+
+Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight)
+ : light(coreLight) , map(&coreMap) {
+}
+
+static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) {
+ return new Light(map, coreLight);
+}
+
+jni::jobject* Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) {
+ std::unique_ptr<Light> peerLight = std::unique_ptr<Light>(initializeLightPeer(map, coreLight));
+ jni::jobject* result = peerLight->createJavaPeer(env);
+ peerLight.release();
+ return result;
+}
+
+jni::Class<Light> Light::javaClass;
+
+jni::jobject* Light::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = Light::javaClass.template GetConstructor<jni::jlong>(env);
+ return Light::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+}
+
+<% for (const property of properties) { -%>
+<% if (property.name == "position") { -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::Object<<%- camelize(property.name) %>> j<%- property.name %>) {
+ using namespace mbgl::android::conversion;
+ auto position = *convert<mbgl::style::<%- camelize(property.name) %>>(env, jposition);
+ light.set<%- camelize(property.name) %>(<%- property.name %>);
+}
+
+jni::Object<Position> Light::get<%- camelize(property.name) %>(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::<%- camelize(property.name) %> <%- property.name %> = light.get<%- camelize(property.name) %>().asConstant();
+ return *convert<jni::Object<<%- camelize(property.name) %>>>(env, <%- property.name %>);
+}
+<% } else { -%>
+<% if(property.name == "color") {-%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::<%- propertyJNIType(property) %> property) {
+ auto color = Color::parse(jni::Make<std::string>(env, property));
+ if (color) {
+ light.set<%- camelize(property.name) %>(color.value());
+ }
+}
+
+jni::String Light::get<%- camelize(property.name) %>(jni::JNIEnv &env) {
+ auto color = light.get<%- camelize(property.name) %>().asConstant();
+ return jni::Make<jni::String>(env, color.stringify());
+}
+<% } else if(property.name == "anchor"){ -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::<%- propertyJNIType(property) %> property) {
+ std::string anchorStr = jni::Make<std::string>(env, property);
+ if (anchorStr.compare("map") == 0) {
+ light.setAnchor(LightAnchorType::Map);
+ } else if (anchorStr.compare("viewport") == 0) {
+ light.setAnchor(LightAnchorType::Viewport);
+ }
+}
+
+jni::String Light::getAnchor(jni::JNIEnv& env) {
+ auto anchorType = light.getAnchor();
+ if (anchorType == LightAnchorType::Map) {
+ return jni::Make<jni::String>(env, "map");
+ } else {
+ return jni::Make<jni::String>(env, "viewport");
+ }
+}
+<% } else { -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv&, jni::<%- propertyJNIType(property) %> property) {
+ light.set<%- camelize(property.name) %>(property);
+}
+
+jni::<%- propertyJNIType(property) %> Light::get<%- camelize(property.name) %>(jni::JNIEnv&) {
+ return light.get<%- camelize(property.name) %>().asConstant();
+}
+<% } -%>
+<% } -%>
+
+<% if (property.transition) { -%>
+jni::Object<TransitionOptions> Light::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.get<%- camelize(property.name) %>Transition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.set<%- camelize(property.name) %>Transition(options);
+}
+
+<% } -%>
+<% } -%>
+void Light::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Light::javaClass = *jni::Class<Light>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+ // Register the peer
+ jni::RegisterNativePeer<Light>(env, Light::javaClass, "nativePtr",<% for(var i = 0; i < properties.length; i++) {%>
+<% if (properties[i].transition) { -%>
+ METHOD(&Light::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"),
+ METHOD(&Light::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"),
+<% } -%>
+ METHOD(&Light::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>"),
+ METHOD(&Light::set<%- camelize(properties[i].name) %>, "nativeSet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>);
+}
+
+} // namespace android
+} // namespace mb
diff --git a/platform/android/src/style/light.hpp b/platform/android/src/style/light.hpp
new file mode 100644
index 0000000000..2c314067be
--- /dev/null
+++ b/platform/android/src/style/light.hpp
@@ -0,0 +1,57 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+#include <mbgl/style/light.hpp>
+#include "transition_options.hpp"
+#include "position.hpp"
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/property_value.hpp>
+
+namespace mbgl {
+namespace android {
+
+using namespace style;
+
+class Light : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; };
+
+ static jni::Class<Light> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::jobject* createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&);
+
+ Light(mbgl::Map&, mbgl::style::Light&);
+
+ void setAnchor(jni::JNIEnv&, jni::String);
+ jni::String getAnchor(jni::JNIEnv&);
+ void setPosition(jni::JNIEnv&, jni::Object<Position>);
+ jni::Object<Position> getPosition(jni::JNIEnv&);
+ void setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getPositionTransition(jni::JNIEnv&);
+ void setColor(jni::JNIEnv&, jni::String);
+ jni::String getColor(jni::JNIEnv&);
+ void setColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getColorTransition(jni::JNIEnv&);
+ void setIntensity(jni::JNIEnv&, jni::jfloat);
+ jni::jfloat getIntensity(jni::JNIEnv&);
+ void setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIntensityTransition(jni::JNIEnv&);
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+protected:
+
+ // Raw reference to the light
+ mbgl::style::Light& light;
+
+ // Map is set when the light is retrieved
+ mbgl::Map* map;
+};
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/light.hpp.ejs b/platform/android/src/style/light.hpp.ejs
new file mode 100644
index 0000000000..18f961b9e0
--- /dev/null
+++ b/platform/android/src/style/light.hpp.ejs
@@ -0,0 +1,59 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+#include <mbgl/style/light.hpp>
+#include "transition_options.hpp"
+#include "position.hpp"
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/property_value.hpp>
+
+namespace mbgl {
+namespace android {
+
+using namespace style;
+
+class Light : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; };
+
+ static jni::Class<Light> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::jobject* createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&);
+
+ Light(mbgl::Map&, mbgl::style::Light&);
+
+<% for (const property of properties) { -%>
+<% if (property.name=="position") {-%>
+ void set<%- camelize(property.name) %>(jni::JNIEnv&, jni::Object<Position>);
+ jni::Object<<%- camelize(property.name) %>> get<%- camelize(property.name) %>(jni::JNIEnv&);
+<% } else { -%>
+ void set<%- camelize(property.name) %>(jni::JNIEnv&, jni::<%- propertyJNIType(property) %>);
+ jni::<%- propertyJNIType(property) %> get<%- camelize(property.name) %>(jni::JNIEnv&);
+<% } -%>
+<% if (property.transition) { -%>
+ void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> get<%- camelize(property.name) %>Transition(jni::JNIEnv&);
+<% } -%>
+<% } -%>
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+protected:
+
+ // Raw reference to the light
+ mbgl::style::Light& light;
+
+ // Map is set when the light is retrieved
+ mbgl::Map* map;
+};
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/position.cpp b/platform/android/src/style/position.cpp
new file mode 100644
index 0000000000..0bbcefcbcd
--- /dev/null
+++ b/platform/android/src/style/position.cpp
@@ -0,0 +1,34 @@
+#include "position.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<Position> Position::fromPosition(jni::JNIEnv& env, jfloat radialCoordinate, jfloat azimuthalAngle, jfloat polarAngle) {
+ static auto method = Position::javaClass.GetStaticMethod<jni::Object<Position> (jfloat, jfloat, jfloat)>(env, "fromPosition");
+ return Position::javaClass.Call(env, method, radialCoordinate, azimuthalAngle, polarAngle);
+}
+
+void Position::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Position::javaClass = *jni::Class<Position>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Position> Position::javaClass;
+
+float Position::getRadialCoordinate(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "radialCoordinate");
+ return position.Get(env, field);
+}
+
+float Position::getAzimuthalAngle(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "azimuthalAngle");
+ return position.Get(env, field);
+}
+
+float Position::getPolarAngle(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "polarAngle");
+ return position.Get(env, field);
+}
+
+} // namespace andr[oid
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/position.hpp b/platform/android/src/style/position.hpp
new file mode 100644
index 0000000000..4aafa853db
--- /dev/null
+++ b/platform/android/src/style/position.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Position : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Position"; };
+
+ static jni::Object<Position> fromPosition(jni::JNIEnv&, jfloat, jfloat, jfloat);
+
+ static jni::Class<Position> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static float getRadialCoordinate(jni::JNIEnv&, jni::Object<Position>);
+ static float getAzimuthalAngle(jni::JNIEnv&, jni::Object<Position>);
+ static float getPolarAngle(jni::JNIEnv&, jni::Object<Position>);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file