summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java74
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java295
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java42
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java44
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java341
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java352
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java53
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java14
-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.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java180
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java36
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java489
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java355
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java297
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java96
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java77
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java145
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java705
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java146
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java757
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java93
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java90
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/overview.html8
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_bearing.pngbin0 -> 1046 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_normal.pngbin0 -> 885 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.pngbin2783 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.pngbin5939 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.pngbin2593 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_bearing.pngbin0 -> 649 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_normal.pngbin0 -> 555 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.pngbin2089 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.pngbin3599 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.pngbin1942 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_bearing.pngbin0 -> 1345 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_normal.pngbin0 -> 1096 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.pngbin3520 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.pngbin8155 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.pngbin3287 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_bearing.pngbin0 -> 1902 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_normal.pngbin0 -> 1586 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.pngbin5057 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.pngbin13246 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.pngbin4676 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_bearing.pngbin0 -> 3022 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_normal.pngbin0 -> 2456 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.pngbin5236 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.pngbin11688 -> 0 bytes
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.pngbin5053 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_mylocationview_background.xml10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml40
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/integers.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml1
74 files changed, 4048 insertions, 1252 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java
new file mode 100644
index 0000000000..211590653a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java
@@ -0,0 +1,74 @@
+package com.mapbox.mapboxsdk;
+
+import android.content.Context;
+import android.text.TextUtils;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
+
+public class MapboxAccountManager {
+
+ private static MapboxAccountManager mapboxAccountManager = null;
+
+ private final String accessToken;
+ private final Context applicationContext;
+
+ /**
+ * MapboxAccountManager should NOT be instantiated directly.
+ * Use @see MapboxAccountManager#getInstance() instead.
+ * @param applicationContext Context used to get ApplicationContext
+ * @param accessToken Mapbox Access Token
+ */
+ private MapboxAccountManager(Context applicationContext, String accessToken) {
+ super();
+ this.applicationContext = applicationContext.getApplicationContext();
+ this.accessToken = accessToken;
+ }
+
+ /**
+ * Primary entry point to Mapbox for implementing developers.
+ * Must be configured in either Application.onCreate() or Launch Activity.onCreate()
+ *
+ * @param context Context used to get Application Context
+ * @param accessToken Mapbox Access Token. You can get one on the Mapbox Web site.
+ * @return MapboxAccountManager instance for app
+ */
+ public static MapboxAccountManager start(Context context, String accessToken) {
+ if (mapboxAccountManager == null) {
+ mapboxAccountManager = new MapboxAccountManager(context, accessToken);
+ }
+ MapboxEventManager eventManager = MapboxEventManager.getMapboxEventManager();
+ eventManager.initialize(mapboxAccountManager.applicationContext, mapboxAccountManager.accessToken);
+ return mapboxAccountManager;
+ }
+
+ /**
+ * Internal Use Only
+ * Get an instance of MapboxAccountManager configured with the app's Access Token
+ *
+ * @return MapboxAccountManager instance for app. May be NULL if not configured yet.
+ */
+ public static MapboxAccountManager getInstance() {
+ return mapboxAccountManager;
+ }
+
+ /**
+ * Access Token for this application
+ * @return Mapbox Access Token
+ */
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ /**
+ * Runtime validation of Access Token
+ *
+ * @param accessToken Access Token to check
+ * @throws InvalidAccessTokenException
+ */
+ public static void validateAccessToken(String accessToken) throws InvalidAccessTokenException {
+ if (TextUtils.isEmpty(accessToken) || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.") && !accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("sk."))) {
+ throw new InvalidAccessTokenException();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
index 114e809b9e..36d56591c8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
@@ -22,7 +22,7 @@ public abstract class Annotation implements Comparable<Annotation> {
* Internal C++ id is stored as unsigned int.
*/
private long id = -1; // -1 unless added to a MapView
- private MapboxMap mapboxMap;
+ protected MapboxMap mapboxMap;
protected Annotation() {
}
@@ -75,19 +75,15 @@ public abstract class Annotation implements Comparable<Annotation> {
} else if (id > annotation.getId()) {
return -1;
}
-
- // Equal
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
+ if (o == null || !(o instanceof Annotation)) return false;
Annotation that = (Annotation) o;
-
- return getId() == that.getId();
+ return id == that.getId();
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
index fe8bf67920..fc2022f9e1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
@@ -6,7 +6,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
/**
* Abstract builder class for composing custom Marker objects.
- * <p/>
+ *
* Extending this class requires implementing Parceable interface.
*
* @param <U> Type of the marker to be composed
@@ -43,4 +43,4 @@ public abstract class BaseMarkerOptions<U extends Marker, T extends BaseMarkerOp
public abstract U getMarker();
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
new file mode 100644
index 0000000000..0cd54fc0f0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
@@ -0,0 +1,295 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.os.Parcelable;
+import android.support.annotation.AnimatorRes;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+/**
+ * Abstract builder class for composing custom MarkerView objects.
+ * <p>
+ * Extending this class requires implementing Parceable interface.
+ * </p>
+ *
+ * @param <U> Type of the marker view to be composed
+ * @param <T> Type of the builder to be used for composing
+ */
+public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends BaseMarkerViewOptions<U, T>> implements Parcelable {
+
+ protected LatLng position;
+ protected String snippet;
+ protected String title;
+ protected Icon icon;
+ protected boolean flat;
+ protected float anchorU = 0.5f;
+ protected float anchorV = 1f;
+ protected float infoWindowAnchorU = 0.5f;
+ protected float infoWindowAnchorV = 0.0f;
+ protected int selectAnimRes;
+ protected int deselectAnimRes;
+ protected int rotation;
+ protected boolean visible = true;
+
+ /**
+ * Default constructor
+ */
+ public BaseMarkerViewOptions() {
+ }
+
+ /**
+ * Set the geographical location of the MarkerView.
+ *
+ * @param position the location to position the MarkerView
+ * @return the object for which the method was called
+ */
+ public T position(@NonNull LatLng position) {
+ this.position = position;
+ return getThis();
+ }
+
+ /**
+ * Set the snippet of the MarkerView.
+ *
+ * @param snippet the snippet of the MarkerView
+ * @return the object for which the method was called
+ */
+ public T snippet(String snippet) {
+ this.snippet = snippet;
+ return getThis();
+ }
+
+ /**
+ * Set the title of the MarkerView.
+ *
+ * @param title the title of the MarkerView
+ * @return the object for which the method was called
+ */
+ public T title(String title) {
+ this.title = title;
+ return getThis();
+ }
+
+ /**
+ * Set the icon of the MarkerView.
+ *
+ * @param icon the icon of the MarkerView
+ * @return the object for which the method was called
+ */
+ public T icon(Icon icon) {
+ this.icon = icon;
+ return getThis();
+ }
+
+ /**
+ * Set the flat state of the MarkerView.
+ *
+ * @param flat the flat state of the MarkerView
+ * @return the object for which the method was called
+ */
+ public T flat(boolean flat) {
+ this.flat = flat;
+ return getThis();
+ }
+
+ /**
+ * Set the anchor of the MarkerView.
+ *
+ * @param u the u-value
+ * @param v the v-value
+ * @return the object for which the method was called
+ */
+ public T anchor(float u, float v) {
+ this.anchorU = u;
+ this.anchorV = v;
+ return getThis();
+ }
+
+ /**
+ * Set the InfoWindow anchor of the MarkerView.
+ *
+ * @param u the u-value
+ * @param v the v-values
+ * @return the object for which the method was called
+ */
+ public T infoWindowAnchor(float u, float v) {
+ this.infoWindowAnchorU = u;
+ this.infoWindowAnchorV = v;
+ return getThis();
+ }
+
+ /**
+ * Set the animator resource to be used when an MarkerView is selected.
+ *
+ * @param selectAnimRes the used animator resource
+ * @return the object for which the method was called
+ */
+ public T selectAnimatorResource(@AnimatorRes int selectAnimRes) {
+ this.selectAnimRes = selectAnimRes;
+ return getThis();
+ }
+
+ /**
+ * Set the animator resource to be used when an MarkerView is deselected.
+ *
+ * @param deselectAnimRes the used animator resource
+ * @return the object for which the method was called
+ */
+ public T deselectAnimatorResource(@AnimatorRes int deselectAnimRes) {
+ this.deselectAnimRes = deselectAnimRes;
+ return getThis();
+ }
+
+ /**
+ * Set the rotation of the MarkerView.
+ *
+ * @param rotation the rotation value
+ * @return the object for which the method was called
+ */
+ public T rotation(int rotation) {
+ this.rotation = rotation;
+ return getThis();
+ }
+
+ /**
+ * Set the visibility state of the MarkerView.
+ *
+ * @param visible the visible state
+ * @return the object for which the method was calleds
+ */
+ public T visible(boolean visible) {
+ this.visible = visible;
+ return getThis();
+ }
+
+ /**
+ * Get the geographical location of the MarkerView.
+ *
+ * @return the geographical location
+ */
+ public LatLng getPosition() {
+ return position;
+ }
+
+ /**
+ * Get the snippet of the MarkerView.
+ *
+ * @return the snippet
+ */
+ public String getSnippet() {
+ return snippet;
+ }
+
+ /**
+ * Get the title of the MarkerView.
+ *
+ * @return the title
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Get the icon of the MarkerView.
+ *
+ * @return the icon
+ */
+ public Icon getIcon() {
+ return icon;
+ }
+
+ /**
+ * Get the flat state of the MarkerView.
+ *
+ * @return the flat state
+ */
+ public boolean isFlat() {
+ return flat;
+ }
+
+ /**
+ * Get the u-value of the MarkerView anchor.
+ *
+ * @return the u-value
+ */
+ public float getAnchorU() {
+ return anchorU;
+ }
+
+ /**
+ * Get the v-value of the MarkerView anchor.
+ *
+ * @return the v-value
+ */
+ public float getAnchorV() {
+ return anchorV;
+ }
+
+ /**
+ * Get the u-value of the MarkerView InfoWindow anchor.
+ *
+ * @return the u-value
+ */
+ public float getInfoWindowAnchorU() {
+ return infoWindowAnchorU;
+ }
+
+ /**
+ * Get the v-value of the MarkerView InfoWindow anchor.
+ *
+ * @return the v-value
+ */
+ public float getInfoWindowAnchorV() {
+ return infoWindowAnchorV;
+ }
+
+ /**
+ * Get the animator resource used for selecting the MarkerView.
+ *
+ * @return the animator resource
+ */
+ public int getSelectAnimRes() {
+ return selectAnimRes;
+ }
+
+ /**
+ * Get the animator resource used for deselecting the MarkerView.
+ *
+ * @return the animator resource
+ */
+ public int getDeselectAnimRes() {
+ return deselectAnimRes;
+ }
+
+ /**
+ * Get the rotation of the MarkerView.
+ *
+ * @return the rotation value
+ */
+ public int getRotation() {
+ return rotation;
+ }
+
+ /**
+ * Get the visibility state of the MarkerView.
+ *
+ * @return the visibility state
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Get the instance of the object for which this method was called.
+ *
+ * @return the object for which the this method was called
+ */
+ public abstract T getThis();
+
+ /**
+ * Get the MarkerView.
+ *
+ * @return the MarkerView created from this builder
+ */
+ public abstract U getMarker();
+}
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 e30b81d4c9..fceeb52713 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
@@ -6,9 +6,10 @@ import com.mapbox.mapboxsdk.maps.MapView;
/**
* Icon is the visual representation of a {@link Marker} on a {@link MapView}.
+ *
* @see Marker
*/
-public final class Icon {
+public class Icon {
private Bitmap mBitmap;
private String mId;
@@ -39,8 +40,13 @@ public final class Icon {
@Override
public int hashCode() {
- int result = mBitmap.hashCode();
- result = 31 * result + mId.hashCode();
+ int result = 0;
+ if (mBitmap != null) {
+ result = mBitmap.hashCode();
+ }
+ if (mId != null) {
+ result = 31 * result + mId.hashCode();
+ }
return result;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
index c1fc9bb0ab..7452ab8fac 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
@@ -30,6 +30,7 @@ public class InfoWindow {
protected WeakReference<View> mView;
private float mMarkerHeightOffset;
+ private float mMarkerWidthOffset;
private float mViewWidthOffset;
private PointF mCoordinates;
private boolean mIsVisible;
@@ -108,9 +109,9 @@ public class InfoWindow {
// Calculate y-offset for update method
mMarkerHeightOffset = -view.getMeasuredHeight() + offsetY;
+ mMarkerWidthOffset = -offsetX;
// Calculate default Android x,y coordinate
-
mCoordinates = mapboxMap.getProjection().toScreenLocation(position);
float x = mCoordinates.x - (view.getMeasuredWidth() / 2) + offsetX;
float y = mCoordinates.y - view.getMeasuredHeight() + offsetY;
@@ -244,7 +245,7 @@ public class InfoWindow {
View view = mView.get();
if (mapboxMap != null && marker != null && view != null) {
mCoordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
- view.setX(mCoordinates.x + mViewWidthOffset);
+ view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset);
view.setY(mCoordinates.y + mMarkerHeightOffset);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
index c2683cbb56..16b219684f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
@@ -4,16 +4,16 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
/**
* Marker is an annotation that shows an icon image at a geographical location.
- * </p>
+ * <p>
* An {@link InfoWindow} can be shown when a Marker is pressed
- * <p/>
+ * </p>
*/
public class Marker extends Annotation {
@@ -21,9 +21,12 @@ public class Marker extends Annotation {
private String snippet;
private Icon icon;
private String title;
- private InfoWindow infoWindow = null;
- private boolean infoWindowShown = false;
+
+ private InfoWindow infoWindow;
+ private boolean infoWindowShown;
+
private int topOffsetPixels;
+ private int rightOffsetPixels;
/**
* Constructor
@@ -39,6 +42,13 @@ public class Marker extends Annotation {
title = baseMarkerOptions.title;
}
+ Marker(BaseMarkerViewOptions baseMarkerViewOptions){
+ position = baseMarkerViewOptions.position;
+ snippet = baseMarkerViewOptions.snippet;
+ icon = baseMarkerViewOptions.icon;
+ title = baseMarkerViewOptions.title;
+ }
+
public LatLng getPosition() {
return position;
}
@@ -130,7 +140,7 @@ public class Marker extends Annotation {
}
private InfoWindow showInfoWindow(InfoWindow iw, MapView mapView) {
- iw.open(mapView, this, getPosition(), 0, topOffsetPixels);
+ iw.open(mapView, this, getPosition(), rightOffsetPixels, topOffsetPixels);
infoWindowShown = true;
return iw;
}
@@ -149,21 +159,11 @@ public class Marker extends Annotation {
this.topOffsetPixels = topOffsetPixels;
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- if (!super.equals(o)) return false;
-
- Marker marker = (Marker) o;
- return !(getPosition() != null ? !getPosition().equals(marker.getPosition()) : marker.getPosition() != null);
- }
-
- @Override
- public int hashCode() {
- int result = super.hashCode();
- result = 31 * result + (getPosition() != null ? getPosition().hashCode() : 0);
- return result;
+ /**
+ * Do not use this method. Used internally by the SDK.
+ */
+ public void setRightOffsetPixels(int rightOffsetPixels) {
+ this.rightOffsetPixels = rightOffsetPixels;
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
index a3df23d96f..7ca3687b0d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
@@ -3,7 +3,6 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -12,9 +11,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
* <p>
* Builder for composing {@link com.mapbox.mapboxsdk.annotations.Marker} objects.
* </p>
- * <p/>
* <h3>Example</h3>
- * <p/>
* <pre>
* mMapView.addMarker(new MarkerOptions()
* .title("Intersection")
@@ -24,30 +21,24 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
*/
public final class MarkerOptions extends BaseMarkerOptions<Marker, MarkerOptions> implements Parcelable {
- public static final Parcelable.Creator<MarkerOptions> CREATOR
- = new Parcelable.Creator<MarkerOptions>() {
- public MarkerOptions createFromParcel(Parcel in) {
- return new MarkerOptions(in);
- }
+ private Marker marker;
- public MarkerOptions[] newArray(int size) {
- return new MarkerOptions[size];
- }
- };
+ public MarkerOptions() {
+ marker = new Marker();
+ }
- private MarkerOptions(Parcel in) {
+ protected MarkerOptions(Parcel in) {
marker = new Marker();
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
snippet(in.readString());
-
- if(in.readByte()!=0){
+ title(in.readString());
+ if (in.readByte() != 0) {
// this means we have an icon
String iconId = in.readString();
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
Icon icon = new Icon(iconId, iconBitmap);
icon(icon);
}
- title(in.readString());
}
@Override
@@ -57,26 +48,20 @@ public final class MarkerOptions extends BaseMarkerOptions<Marker, MarkerOptions
@Override
public int describeContents() {
- return hashCode();
+ return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(getPosition(), flags);
out.writeString(getSnippet());
+ out.writeString(getTitle());
Icon icon = getIcon();
out.writeByte((byte) (icon != null ? 1 : 0));
if (icon != null) {
out.writeString(getIcon().getId());
out.writeParcelable(getIcon().getBitmap(), flags);
}
- out.writeString(getTitle());
- }
-
- private Marker marker;
-
- public MarkerOptions() {
- marker = new Marker();
}
/**
@@ -108,6 +93,17 @@ public final class MarkerOptions extends BaseMarkerOptions<Marker, MarkerOptions
return icon;
}
+ public static final Parcelable.Creator<MarkerOptions> CREATOR
+ = new Parcelable.Creator<MarkerOptions>() {
+ public MarkerOptions createFromParcel(Parcel in) {
+ return new MarkerOptions(in);
+ }
+
+ public MarkerOptions[] newArray(int size) {
+ return new MarkerOptions[size];
+ }
+ };
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
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
new file mode 100644
index 0000000000..3e51044643
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -0,0 +1,341 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+
+/**
+ * MarkerView is an annotation that shows an View at a geographical location.
+ * <p>
+ * This class uses {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter} to adapt a
+ * MarkerView model to an Android SDK {@link android.view.View} object.
+ * </p>
+ * <p>
+ * An {@link InfoWindow} can be shown when a MarkerView is pressed
+ * </p>
+ */
+public class MarkerView extends Marker {
+
+ private MarkerViewManager markerViewManager;
+
+ private float anchorU;
+ private float anchorV;
+
+ private float offsetX;
+ private float offsetY;
+
+ private float infoWindowAnchorU;
+ private float infoWindowAnchorV;
+
+ private boolean flat;
+ private boolean visible = true;
+
+ private int selectAnimRes;
+ private int deselectAnimRes;
+
+ private float tiltValue;
+ private float rotation;
+ private float alpha = 1;
+
+ /**
+ * Publicly hidden default constructor
+ */
+ MarkerView() {
+ }
+
+ /**
+ * Creates a instance of MarkerView using the builder of MarkerView
+ *
+ * @param baseMarkerViewOptions the builder used to construct the MarkerView
+ */
+ public MarkerView(BaseMarkerViewOptions baseMarkerViewOptions) {
+ super(baseMarkerViewOptions);
+ this.anchorU = baseMarkerViewOptions.getAnchorU();
+ this.anchorV = baseMarkerViewOptions.getAnchorV();
+ this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU();
+ this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV();
+ this.flat = baseMarkerViewOptions.isFlat();
+ this.selectAnimRes = baseMarkerViewOptions.getSelectAnimRes();
+ this.deselectAnimRes = baseMarkerViewOptions.getDeselectAnimRes();
+ this.infoWindowAnchorU = baseMarkerViewOptions.infoWindowAnchorU;
+ this.infoWindowAnchorV = baseMarkerViewOptions.infoWindowAnchorV;
+ this.anchorU = baseMarkerViewOptions.anchorU;
+ this.anchorV = baseMarkerViewOptions.anchorV;
+ }
+
+ /**
+ * Specifies the anchor being set on a particular point point of the MarkerView.
+ * <p>
+ * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)
+ * is the top-left corner of the image, and (1, 1) is the bottom-right corner.
+ * </p>
+ *
+ * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1])
+ * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1])
+ */
+ public void setAnchor(float u, float v) {
+ this.anchorU = u;
+ this.anchorV = v;
+ }
+
+ /**
+ * Get the horizontal distance, normalized to [0, 1], of the anchor from the left edge.
+ *
+ * @return the u-value of the anchor
+ */
+ public float getAnchorU() {
+ return anchorU;
+ }
+
+ /**
+ * Get the vertical distance, normalized to [0, 1], of the anchor from the top edge.
+ *
+ * @return the v-value of the anchor
+ */
+ public float getAnchorV() {
+ return anchorV;
+ }
+
+ /**
+ * Internal method to set the horizontal calculated offset.
+ * <p>
+ * These are calculated based on the View bounds and the provided anchor.
+ * </p>
+ *
+ * @param x the x-value of the offset
+ */
+ void setOffsetX(float x) {
+ offsetX = x;
+ }
+
+ /**
+ * Internal method to set the vertical calculated offset.
+ * <p>
+ * These are calculated based on the View bounds and the provided anchor.
+ * </p>
+ *
+ * @param y the y-value of the offset
+ */
+ void setOffsetY(float y) {
+ offsetY = y;
+ }
+
+ /**
+ * Internal method to get the horizontal calculated offset
+ *
+ * @return the calculated horizontal offset
+ */
+ float getOffsetX() {
+ return offsetX;
+ }
+
+ /**
+ * Internal method to get the vertical calculated offset
+ *
+ * @return the calculated vertical offset
+ */
+ float getOffsetY() {
+ return offsetY;
+ }
+
+ /**
+ * Specifies the anchor point of the info window on the View of the MarkerView.
+ * <p>
+ * This is specified in the same coordinate system as the anchor.
+ * </p>
+ * <p>
+ * The default is the top middle of the View.
+ * </p>
+ *
+ * @param u u-coordinate of the info window anchor, as a ratio of the image width (in the range [0, 1])
+ * @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1])
+ * @see #setAnchor(float, float) for more details.
+ */
+ public void setInfoWindowAnchor(float u, float v) {
+ this.infoWindowAnchorU = u;
+ this.infoWindowAnchorV = v;
+ }
+
+ /**
+ * Get the horizontal distance, normalized to [0, 1], of the info window anchor from the left edge.
+ *
+ * @return the u value of the InfoWindow anchor.
+ */
+ public float getInfoWindowAnchorU() {
+ return infoWindowAnchorU;
+ }
+
+ /**
+ * Get the vertical distance, normalized to [0, 1], of the info window anchor from the top edge.
+ *
+ * @return the v value of the InfoWindow anchor.
+ */
+ public float getInfoWindowAnchorV() {
+ return infoWindowAnchorV;
+ }
+
+ /**
+ * Get the flat state of a MarkerView.
+ *
+ * @return true is the MarkerView is flat; false is the MarkerView is billboard
+ */
+ public boolean isFlat() {
+ return flat;
+ }
+
+ /**
+ * Sets whether this marker should be flat against the map true or a billboard facing the camera false.
+ *
+ * @param flat the flat state of the MarkerView
+ */
+ public void setFlat(boolean flat) {
+ this.flat = flat;
+ }
+
+ /**
+ * Get the animator resource used to animate to the selected state of a MarkerView.
+ *
+ * @return the animator resource used
+ */
+ public int getSelectAnimRes() {
+ return selectAnimRes;
+ }
+
+ /**
+ * Set the animator resource used to animate to the deselected state of a MarkerView.
+ *
+ * @param selectAnimRes the animator resource used
+ */
+ public void setSelectAnimRes(int selectAnimRes) {
+ this.selectAnimRes = selectAnimRes;
+ }
+
+ /**
+ * Get the animator resource used to animate to the deslected state of a MarkerView.
+ *
+ * @return the animator resource used
+ */
+ public int getDeselectAnimRes() {
+ return deselectAnimRes;
+ }
+
+ /**
+ * Set the animator resource used to animate to the selected state of a MarkerView.
+ *
+ * @param deselectAnimRes the animator resource used
+ */
+ public void setDeselectAnimRes(int deselectAnimRes) {
+ this.deselectAnimRes = deselectAnimRes;
+ }
+
+ /**
+ * Internal method to get the current tilted value of a MarkerView.
+ *
+ * @return the tilted value
+ */
+ float getTilt() {
+ return tiltValue;
+ }
+
+ /**
+ * Internal method to set the current titled value of a MarkerView.
+ *
+ * @param tiltValue the tilted value to set
+ */
+ void setTilt(float tiltValue) {
+ this.tiltValue = tiltValue;
+ }
+
+ /**
+ * Set the visible state of a MarkerView.
+ *
+ * @param visible true will make the MarkerView visible, false will hide the MarkerViews
+ */
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ if (markerViewManager != null) {
+ markerViewManager.animateVisible(this, visible);
+ }
+ }
+
+ /**
+ * Returns the visible state of the MarkerView.
+ *
+ * @return the visible state
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Set the rotation value of the MarkerView.
+ * <p>
+ * This will result in animating the rotation of the MarkerView using an rotation animator
+ * from current value to the provided parameter value.
+ * </p>
+ *
+ * @param rotation the rotation value to animate to
+ */
+ public void setRotation(float rotation) {
+ this.rotation = rotation;
+ if (markerViewManager != null) {
+ markerViewManager.animateRotation(this, rotation);
+ }
+ }
+
+ /**
+ * Get the rotation value of the MarkerView.
+ *
+ * @return the rotation value
+ */
+ public float getRotation() {
+ return rotation;
+ }
+
+ /**
+ * Get the alpha value of the MarkerView.
+ *
+ * @return the alpha value
+ */
+ public float getAlpha() {
+ return alpha;
+ }
+
+ /**
+ * Set the alpha value of the MarkerView.
+ * <p>
+ * This will result in animating the alpha of the MarkerView using an alpha animator
+ * from current value to the provided parameter value.
+ * </p>
+ *
+ * @param alpha the alpha value to animate to
+ */
+ public void setAlpha(float alpha) {
+ this.alpha = alpha;
+ if (markerViewManager != null) {
+ markerViewManager.animateAlpha(this, alpha);
+ }
+ }
+
+ /**
+ * Set the MapboxMap associated tot the MapView containing the MarkerView.
+ * <p>
+ * This method is used to instantiate the MarkerView and provide an instance of {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}
+ * </p>
+ *
+ * @param mapboxMap the MapboxMap instances
+ */
+ @Override
+ public void setMapboxMap(MapboxMap mapboxMap) {
+ super.setMapboxMap(mapboxMap);
+ markerViewManager = mapboxMap.getMarkerViewManager();
+ }
+
+ /**
+ * Get the String representation of a MarkerView.
+ *
+ * @return the String representation
+ */
+ @Override
+ public String toString() {
+ return "MarkerView [position[" + getPosition() + "]]";
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
new file mode 100644
index 0000000000..d9fc9e62ae
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
@@ -0,0 +1,352 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.graphics.PointF;
+import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pools;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Projection;
+import com.mapbox.mapboxsdk.utils.AnimatorUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Interface for interacting with ViewMarkers objects inside of a MapView.
+ * <p>
+ * This class is responsible for managing a {@link MarkerView} item.
+ * </p>
+ */
+public class MarkerViewManager {
+
+ private Map<MarkerView, View> mMarkerViewMap;
+ private MapboxMap mapboxMap;
+ private MapView mapView;
+ private List<MapboxMap.MarkerViewAdapter> markerViewAdapters;
+ private long mViewMarkerBoundsUpdateTime;
+ private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener;
+
+ /**
+ * Creates an instance of MarkerViewManager.
+ *
+ * @param mapboxMap the MapboxMap associated with the MarkerViewManager
+ * @param mapView the MapView associated with the MarkerViewManager
+ */
+ public MarkerViewManager(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) {
+ this.mapboxMap = mapboxMap;
+ this.markerViewAdapters = new ArrayList<>();
+ this.mapView = mapView;
+ mMarkerViewMap = new HashMap<>();
+ }
+
+ /**
+ * Animate a MarkerView to a given rotation.
+ * <p>
+ * The {@link MarkerView} will be rotated from its current rotation to the given rotation.
+ * </p>
+ *
+ * @param marker the MarkerView to rotate
+ * @param rotation the rotation value
+ */
+ public void animateRotation(@NonNull MarkerView marker, float rotation) {
+ View convertView = mMarkerViewMap.get(marker);
+ if (convertView != null) {
+ AnimatorUtils.rotate(convertView, rotation);
+ }
+ }
+
+ /**
+ * Animate a MarkerView to a given alpha value.
+ * <p>
+ * The {@link MarkerView} will be transformed from its current alpha value to the given value.
+ * </p>
+ *
+ * @param marker the MarkerView to change its alpha value
+ * @param alpha the alpha value
+ */
+ public void animateAlpha(@NonNull MarkerView marker, float alpha) {
+ View convertView = mMarkerViewMap.get(marker);
+ if (convertView != null) {
+ AnimatorUtils.alpha(convertView, alpha);
+ }
+ }
+
+ /**
+ * Animate a MarkerVIew to be visible or invisible
+ * <p>
+ * The {@link MarkerView} will be made {@link View#VISIBLE} or {@link View#GONE}.
+ * </p>
+ *
+ * @param marker the MarkerView to change its visibility
+ * @param visible the flag indicating if MarkerView is visible
+ */
+ public void animateVisible(@NonNull MarkerView marker, boolean visible) {
+ View convertView = mMarkerViewMap.get(marker);
+ if (convertView != null) {
+ convertView.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ /**
+ * Updates the position of MarkerViews currently found in the viewport.
+ * <p>
+ * The collection of {@link MarkerView} will be iterated and each item position will be updated.
+ * If an item is View state is not visible and its related flag is set to visible,
+ * The {@link MarkerView} will be animated to visible using alpha animation.
+ * </p>
+ */
+ public void update() {
+ View convertView;
+ for (MarkerView marker : mMarkerViewMap.keySet()) {
+ convertView = mMarkerViewMap.get(marker);
+ if (convertView != null) {
+ PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
+ int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth());
+ int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight());
+
+ marker.setOffsetX(x);
+ marker.setOffsetY(y);
+
+ convertView.setX(point.x - x);
+ convertView.setY(point.y - y);
+
+ if (marker.isVisible() && convertView.getVisibility() == View.GONE) {
+ convertView.animate().cancel();
+ convertView.setAlpha(0);
+ AnimatorUtils.alpha(convertView, 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set tilt on every non flat MarkerView currently shown in the Viewport.
+ *
+ * @param tilt the tilt value
+ */
+ public void setTilt(float tilt) {
+ View convertView;
+ for (MarkerView markerView : mMarkerViewMap.keySet()) {
+ if (markerView.isFlat()) {
+ convertView = mMarkerViewMap.get(markerView);
+ if (convertView != null) {
+ markerView.setTilt(tilt);
+ convertView.setRotationX(tilt);
+ }
+ }
+ }
+ }
+
+ /**
+ * Animate a MarkerView to a deselected state.
+ * <p>
+ * The {@link MarkerView#getDeselectAnimRes()} will be called to get the related animation.
+ * If non are provided, no animation will be started.
+ * </p>
+ *
+ * @param marker the MarkerView to deselect
+ */
+ public void deselect(@NonNull MarkerView marker) {
+ final View convertView = mMarkerViewMap.get(marker);
+ if (convertView != null) {
+ int deselectAnimatorRes = marker.getDeselectAnimRes();
+ if (deselectAnimatorRes != 0) {
+ AnimatorUtils.animate(convertView, deselectAnimatorRes);
+ }
+ }
+ }
+
+ /**
+ * Remove a MarkerView from a map.
+ * <p>
+ * The {@link MarkerView} will be removed using an alpha animation and related {@link View}
+ * will be released to the {@link android.support.v4.util.Pools.SimplePool} from the related
+ * {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}. It's possible to remove
+ * the {@link MarkerView} from the underlying collection if needed.
+ * </p>
+ *
+ * @param marker the MarkerView to remove
+ * @param removeFromMap flag indicating if a MarkerView will be removed from the collection.
+ */
+ public void removeMarkerView(MarkerView marker, boolean removeFromMap) {
+ final View viewHolder = mMarkerViewMap.get(marker);
+ if (viewHolder != null && marker != null) {
+ for (final MapboxMap.MarkerViewAdapter<?> adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass() == marker.getClass()) {
+
+ // get pool of Views associated to an adapter
+ final Pools.SimplePool<View> viewPool = adapter.getViewReusePool();
+
+ // cancel ongoing animations
+ viewHolder.animate().cancel();
+ viewHolder.setAlpha(1);
+ AnimatorUtils.alpha(viewHolder, 0, new AnimatorUtils.OnAnimationEndListener() {
+ @Override
+ public void onAnimationEnd() {
+ viewHolder.setVisibility(View.GONE);
+ viewPool.release(viewHolder);
+ }
+ });
+ }
+ }
+ }
+ if (removeFromMap) {
+ mMarkerViewMap.remove(marker);
+ }
+ }
+
+ /**
+ * Add a MarkerViewAdapter.
+ *
+ * @param markerViewAdapter the MarkerViewAdapter to add
+ */
+ public void addMarkerViewAdapter(@Nullable MapboxMap.MarkerViewAdapter markerViewAdapter) {
+ if (!markerViewAdapters.contains(markerViewAdapter)) {
+ markerViewAdapters.add(markerViewAdapter);
+ invalidateViewMarkersInBounds();
+ }
+ }
+
+ /**
+ * Get all MarkerViewAdapters associated with this MarkerViewManager.
+ *
+ * @return a List of MarkerViewAdapters
+ */
+ public List<MapboxMap.MarkerViewAdapter> getMarkerViewAdapters() {
+ return markerViewAdapters;
+ }
+
+
+ /**
+ * Register a callback to be invoked when this view is clicked.
+ *
+ * @param listener the callback to be invoked
+ */
+ public void setOnMarkerViewClickListener(@Nullable MapboxMap.OnMarkerViewClickListener listener) {
+ onMarkerViewClickListener = listener;
+ }
+
+ /**
+ * Schedule that ViewMarkers found in the viewport are invalidated.
+ * <p>
+ * This method is rate limited, and {@link #invalidateViewMarkersInBounds} will only be called
+ * once each 250 ms.
+ * </p>
+ */
+ public void scheduleViewMarkerInvalidation() {
+ if (!markerViewAdapters.isEmpty()) {
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime < mViewMarkerBoundsUpdateTime) {
+ return;
+ }
+ invalidateViewMarkersInBounds();
+ mViewMarkerBoundsUpdateTime = currentTime + 250;
+ }
+ }
+
+ /**
+ * Invalidate the ViewMarkers found in the viewport.
+ * <p>
+ * This method will remove any markers that aren't in the viewport any more and will add new
+ * ones for each found Marker in the changed viewport.
+ * </p>
+ */
+ public void invalidateViewMarkersInBounds() {
+ Projection projection = mapboxMap.getProjection();
+ List<MarkerView> markers = mapView.getMarkerViewsInBounds(projection.getVisibleRegion().latLngBounds);
+ View convertView;
+
+ // remove old markers
+ Iterator<MarkerView> iterator = mMarkerViewMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ MarkerView m = iterator.next();
+ if (!markers.contains(m)) {
+ // remove marker
+ convertView = mMarkerViewMap.get(m);
+ int deselectAnimRes = m.getDeselectAnimRes();
+ if (deselectAnimRes != 0) {
+ AnimatorUtils.animate(convertView, deselectAnimRes, 0);
+ }
+ removeMarkerView(m, false);
+ iterator.remove();
+ }
+ }
+
+ // introduce new markers
+ for (final MarkerView marker : markers) {
+ if (!mMarkerViewMap.containsKey(marker)) {
+ for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass() == marker.getClass()) {
+ convertView = (View) adapter.getViewReusePool().acquire();
+ final View adaptedView = adapter.getView(marker, convertView, mapView);
+ if (adaptedView != null) {
+
+ // tilt
+ adaptedView.setRotationX(marker.getTilt());
+
+ // rotation
+ adaptedView.setRotation(marker.getRotation());
+
+ // alpha
+ adaptedView.setAlpha(marker.getAlpha());
+
+ // visible
+ adaptedView.setVisibility(marker.isVisible() ? View.VISIBLE : View.GONE);
+
+ if (mapboxMap.getSelectedMarkers().contains(marker)) {
+ // if a marker to be shown was selected
+ // replay that animation with duration 0
+ int selectAnimRes = marker.getSelectAnimRes();
+ if (selectAnimRes != 0) {
+ AnimatorUtils.animate(convertView, selectAnimRes, 0);
+ }
+ }
+
+ final int animSelectRes = marker.getSelectAnimRes();
+ adaptedView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ boolean clickHandled = false;
+ if (onMarkerViewClickListener != null) {
+ clickHandled = onMarkerViewClickListener.onMarkerClick(marker, v, adapter);
+ }
+
+ if (!clickHandled) {
+ // InfoWindow offset
+ int infoWindowOffsetX = (int) ((adaptedView.getWidth() * marker.getInfoWindowAnchorU()) - marker.getOffsetX());
+ int infoWindowOffsetY = (int) ((adaptedView.getHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY());
+ marker.setTopOffsetPixels(infoWindowOffsetY);
+ marker.setRightOffsetPixels(infoWindowOffsetX);
+
+ if (animSelectRes != 0) {
+ AnimatorUtils.animate(v, animSelectRes, new AnimatorUtils.OnAnimationEndListener() {
+ @Override
+ public void onAnimationEnd() {
+ mapboxMap.selectMarker(marker);
+ }
+ });
+ } else {
+ mapboxMap.selectMarker(marker);
+ }
+ }
+ }
+ });
+
+ mMarkerViewMap.put(marker, adaptedView);
+ if (convertView == null) {
+ mapView.addView(adaptedView);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
new file mode 100644
index 0000000000..0c9faed355
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
@@ -0,0 +1,115 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+/**
+ * builder class for composing MarkerView objects.
+ * <p>
+ * Do not extend this class directly but extend BaseMarkerViewOptions instead.
+ * </p>
+ */
+public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerViewOptions> {
+
+ private MarkerView marker;
+
+ public MarkerViewOptions() {
+ marker = new MarkerView();
+ }
+
+ protected MarkerViewOptions(Parcel in) {
+ marker = new MarkerView();
+ position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
+ snippet(in.readString());
+ title(in.readString());
+ flat(in.readByte() != 0);
+ anchor(in.readFloat(), in.readFloat());
+ infoWindowAnchor(in.readFloat(), in.readFloat());
+ selectAnimatorResource(in.readInt());
+ deselectAnimatorResource(in.readInt());
+ rotation(in.readInt());
+ visible(in.readByte() != 0);
+ if (in.readByte() != 0) {
+ // this means we have an icon
+ String iconId = in.readString();
+ Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ Icon icon = new Icon(iconId, iconBitmap);
+ icon(icon);
+ }
+ }
+
+ @Override
+ public MarkerViewOptions getThis() {
+ return this;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(getPosition(), flags);
+ out.writeString(getSnippet());
+ out.writeString(getTitle());
+ out.writeByte((byte) (isFlat() ? 1 : 0));
+ out.writeFloat(getAnchorU());
+ out.writeFloat(getAnchorV());
+ out.writeFloat(getInfoWindowAnchorU());
+ out.writeFloat(getInfoWindowAnchorV());
+ out.writeInt(getSelectAnimRes());
+ out.writeInt(getDeselectAnimRes());
+ out.writeInt(getRotation());
+ out.writeByte((byte) (isVisible() ? 1 : 0));
+ Icon icon = getIcon();
+ out.writeByte((byte) (icon != null ? 1 : 0));
+ if (icon != null) {
+ out.writeString(getIcon().getId());
+ out.writeParcelable(getIcon().getBitmap(), flags);
+ }
+ }
+
+ @Override
+ public MarkerView getMarker() {
+ marker.setPosition(position);
+ marker.setSnippet(snippet);
+ marker.setTitle(title);
+ marker.setIcon(icon);
+ marker.setFlat(flat);
+ marker.setAnchor(anchorU, anchorV);
+ marker.setInfoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV);
+ marker.setSelectAnimRes(selectAnimRes);
+ marker.setDeselectAnimRes(deselectAnimRes);
+ marker.setRotation(rotation);
+ marker.setVisible(visible);
+ return marker;
+ }
+
+ public static final Parcelable.Creator<MarkerViewOptions> CREATOR
+ = new Parcelable.Creator<MarkerViewOptions>() {
+ public MarkerViewOptions createFromParcel(Parcel in) {
+ return new MarkerViewOptions(in);
+ }
+
+ public MarkerViewOptions[] newArray(int size) {
+ return new MarkerViewOptions[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MarkerViewOptions that = (MarkerViewOptions) o;
+ return marker != null ? marker.equals(that.marker) : that.marker == null;
+ }
+
+ @Override
+ public int hashCode() {
+ return marker != null ? marker.hashCode() : 0;
+ }
+}
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 679a474ae7..f9346e21d6 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
@@ -70,7 +70,7 @@ public final class CameraPosition implements Parcelable {
@Override
public int describeContents() {
- return hashCode();
+ return 0;
}
@Override
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 763ab8d664..028d077a09 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
@@ -56,7 +56,6 @@ public final class CameraUpdateFactory {
return newLatLngBounds(bounds, padding, padding, padding, padding);
}
-
/**
* Returns a CameraUpdate that transforms the camera such that the specified latitude/longitude
* bounds are centered on screen at the greatest possible zoom level.
@@ -227,11 +226,18 @@ public final class CameraUpdateFactory {
// Get required objects
Projection projection = mapboxMap.getProjection();
UiSettings uiSettings = mapboxMap.getUiSettings();
- RectF padding = getPadding();
+
+ // calculate correct padding
+ int[] mapPadding = mapboxMap.getPadding();
+ RectF latLngPadding = getPadding();
+ RectF padding = new RectF(latLngPadding.left + mapPadding[0],
+ latLngPadding.top + mapPadding[1],
+ latLngPadding.right + mapPadding[2],
+ latLngPadding.bottom + mapPadding[3]);
// Calculate the bounds of the possibly rotated shape with respect to the viewport
- PointF nePixel = new PointF(-10000, -10000);
- PointF swPixel = new PointF(10000, 10000);
+ PointF nePixel = new PointF(-Float.MAX_VALUE, -Float.MAX_VALUE);
+ PointF swPixel = new PointF(Float.MAX_VALUE, Float.MAX_VALUE);
float viewportHeight = uiSettings.getHeight();
for (LatLng latLng : getBounds().toLatLngs()) {
PointF pixel = projection.toScreenLocation(latLng);
@@ -241,16 +247,20 @@ public final class CameraUpdateFactory {
nePixel.y = Math.max(nePixel.y, viewportHeight - pixel.y);
}
- // Calculate wid=th/height
+ // Calculate width/height
float width = nePixel.x - swPixel.x;
float height = nePixel.y - swPixel.y;
+ double zoom = 0;
+ float minScale = 1;
// Calculate the zoom level
- float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width;
- float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height;
- float minScale = scaleX < scaleY ? scaleX : scaleY;
- double zoom = projection.calculateZoom(minScale);
- zoom = MathUtils.clamp(zoom, (float) mapboxMap.getMinZoom(), (float) mapboxMap.getMaxZoom());
+ if (padding != null) {
+ float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width;
+ float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height;
+ minScale = scaleX < scaleY ? scaleX : scaleY;
+ zoom = projection.calculateZoom(minScale);
+ zoom = MathUtils.clamp(zoom, (float) mapboxMap.getMinZoom(), (float) mapboxMap.getMaxZoom());
+ }
// Calculate the center point
PointF paddedNEPixel = new PointF(nePixel.x + padding.right / minScale, nePixel.y + padding.top / minScale);
@@ -291,13 +301,22 @@ public final class CameraUpdateFactory {
// Convert point to LatLng
LatLng latLng = projection.fromScreenLocation(targetPoint);
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- return new CameraPosition.Builder()
- .target(latLng)
- .zoom(cameraPosition.zoom)
- .tilt(cameraPosition.tilt)
- .bearing(cameraPosition.bearing)
- .build();
+ CameraPosition previousPosition = mapboxMap.getCameraPosition();
+ if (latLng != null) {
+ return new CameraPosition.Builder()
+ .target(latLng)
+ .zoom(previousPosition.zoom)
+ .tilt(previousPosition.tilt)
+ .bearing(previousPosition.bearing)
+ .build();
+ } else {
+ return new CameraPosition.Builder(true)
+ .tilt(previousPosition.tilt)
+ .zoom(previousPosition.zoom)
+ .bearing(previousPosition.bearing)
+ .target(previousPosition.target)
+ .build();
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
index 475489f621..ece992ad54 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.constants;
+import android.content.Context;
import java.util.Locale;
/**
@@ -14,7 +15,9 @@ public class MapboxConstants {
/**
* Key used to store access token in AndroidManifest.xml
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
*/
+ @Deprecated
public static final String KEY_META_DATA_MANIFEST = "com.mapbox.AccessToken";
/**
@@ -33,6 +36,11 @@ public class MapboxConstants {
public static final int ANIMATION_DURATION = 300;
/**
+ * Default short animation time
+ */
+ public static final int ANIMATION_DURATION_SHORT = 150;
+
+ /**
* The currently supported minimum zoom level.
*/
public static final float MINIMUM_ZOOM = 0.0f;
@@ -71,14 +79,16 @@ public class MapboxConstants {
public static final String STATE_HAS_SAVED_STATE = "savedState";
public static final String STATE_CAMERA_POSITION = "cameraPosition";
public static final String STATE_ZOOM_ENABLED = "zoomEnabled";
+ public static final String STATE_ZOOM_ENABLED_CHANGE = "zoomEnabledChange";
public static final String STATE_SCROLL_ENABLED = "scrollEnabled";
+ public static final String STATE_SCROLL_ENABLED_CHANGE = "scrollEnabledChange";
public static final String STATE_ROTATE_ENABLED = "rotateEnabled";
+ public static final String STATE_ROTATE_ENABLED_CHANGE = "rotateEnabledChange";
public static final String STATE_TILT_ENABLED = "tiltEnabled";
+ public static final String STATE_TILT_ENABLED_CHANGE = "tiltEnabledChange";
public static final String STATE_ZOOM_CONTROLS_ENABLED = "zoomControlsEnabled";
public static final String STATE_DEBUG_ACTIVE = "debugActive";
public static final String STATE_STYLE_URL = "styleUrl";
- public static final String STATE_ACCESS_TOKEN = "accessToken";
- public static final String STATE_DEFAULT_TRANSITION_DURATION = "defaultTransitionDuration";
public static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled";
public static final String STATE_MY_LOCATION_TRACKING_MODE = "myLocationTracking";
public static final String STATE_MY_BEARING_TRACKING_MODE = "myBearingTracking";
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 383a85417c..929df2da77 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
@@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -12,7 +12,7 @@ import java.lang.annotation.RetentionPolicy;
* MyBearingTracking exposes different types bearing tracking modes.
*
* @see MapView#setMyBearingTrackingMode(int)
- * @see UserLocationView#setMyBearingTrackingMode(int)
+ * @see MyLocationView#setMyBearingTrackingMode(int)
*/
public class MyBearingTracking {
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 9b0ae7285e..b2a49c6454 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
@@ -3,7 +3,7 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -12,7 +12,7 @@ import java.lang.annotation.RetentionPolicy;
* MyLocationTracking exposes different types of locational tracking modes.
*
* @see MapView#setMyLocationTrackingMode(int)
- * @see UserLocationView#setMyLocationTrackingMode(int)
+ * @see MyLocationView#setMyLocationTrackingMode(int)
*/
public class MyLocationTracking {
@@ -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 UserLocationView}
+ * 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 31c146b43e..aa24d58656 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
@@ -1,11 +1,10 @@
package com.mapbox.mapboxsdk.constants;
import android.support.annotation.StringDef;
-
import com.mapbox.mapboxsdk.maps.MapView;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+
/**
* <p>
* Style provides URLs to several professional styles designed by Mapbox.
@@ -17,10 +16,154 @@ import java.lang.annotation.RetentionPolicy;
public class Style {
/**
+ * Mapbox Streets: A complete basemap, perfect for incorporating your own data.
+ */
+ private static final String MAPBOX_STREETS_BASE = "mapbox://styles/mapbox/streets-v%d";
+ /**
+ * Outdoors: A general-purpose style tailored to outdoor activities.
+ */
+ private static final String OUTDOORS_BASE = "mapbox://styles/mapbox/outdoors-v%d";
+ /**
+ * Light: Subtle light backdrop for data visualizations.
+ */
+ private static final String LIGHT_BASE = "mapbox://styles/mapbox/light-v%d";
+ /**
+ * Dark: Subtle dark backdrop for data visualizations.
+ */
+ private static final String DARK_BASE = "mapbox://styles/mapbox/dark-v%d";
+ /**
+ * Satellite: A beautiful global satellite and aerial imagery layer.
+ */
+ private static final String SATELLITE_BASE = "mapbox://styles/mapbox/satellite-v%d";
+ /**
+ * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels.
+ */
+ private static final String SATELLITE_STREETS_BASE = "mapbox://styles/mapbox/satellite-streets-v%d";
+
+ /**
+ * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels (Version 8).
+ */
+ private static final String SATELLITE_STREETS_V8 = "mapbox://styles/mapbox/satellite-hybrid-v8";
+
+ /**
+ * Get versioned url of Mapbox streets style.
+ * <p>
+ * <ul>
+ * <li>Current default version is 9.</li>
+ * </ul
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getMapboxStreetsUrl(int version) {
+ return String.format(MapboxConstants.MAPBOX_LOCALE, MAPBOX_STREETS_BASE, version);
+ }
+
+ /**
+ * Get versioned url of Outdoors streets style.
+ * <p>
+ * <ul>
+ * <li>Current version is 9.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getOutdoorsStyleUrl(int version) {
+ return String.format(MapboxConstants.MAPBOX_LOCALE, OUTDOORS_BASE, version);
+ }
+
+ /**
+ * Get versioned url of Light style.
+ * <p>
+ * <ul>
+ * <li>Current default version is 9.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getLightStyleUrl(int version) {
+ return String.format(MapboxConstants.MAPBOX_LOCALE, LIGHT_BASE, version);
+ }
+
+ /**
+ * Get versioned url of Dark style.
+ * <p>
+ * <ul>
+ * <li>Current default version is 9.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getDarkStyleUrl(int version) {
+ return String.format(MapboxConstants.MAPBOX_LOCALE, DARK_BASE, version);
+ }
+
+ /**
+ * Get versioned url of Satellite style.
+ * <p>
+ * <ul>
+ * <li>Current version is 9.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getSatelliteStyleUrl(int version) {
+ return String.format(MapboxConstants.MAPBOX_LOCALE, SATELLITE_BASE, version);
+ }
+
+ /**
+ * Get versioned url of Satellite streets style.
+ * <p>
+ * <ul>
+ * <li>Current version is 9.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
+ * </p>
+ *
+ * @param version the version of the style.
+ * @return uri to load style from
+ */
+ public static String getSatelliteStreetsStyleUrl(int version) {
+ if (version == 8) {
+ return SATELLITE_STREETS_V8;
+ }
+ return String.format(MapboxConstants.MAPBOX_LOCALE, SATELLITE_STREETS_BASE, version);
+ }
+
+ /**
* Indicates the parameter accepts one of the values from {@link Style}.
+ *
+ * @deprecated use dedicated versioned methods in {@link Style} instead.
*/
@StringDef({MAPBOX_STREETS, EMERALD, LIGHT, DARK, SATELLITE, SATELLITE_STREETS})
@Retention(RetentionPolicy.SOURCE)
+ @Deprecated
public @interface StyleUrl {
}
@@ -28,28 +171,49 @@ public class Style {
/**
* Mapbox Streets: A complete basemap, perfect for incorporating your own data.
+ *
+ * @deprecated use {@link #getMapboxStreetsUrl(int)} instead.
*/
- public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v8";
+ @Deprecated
+ public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v9";
+
/**
* Emerald: A versatile style, with emphasis on road networks and public transit.
+ *
+ * @deprecated this style has been deprecated and will be removed in future versions.
*/
+ @Deprecated
public static final String EMERALD = "mapbox://styles/mapbox/emerald-v8";
+
/**
* Light: Subtle light backdrop for data visualizations.
+ *
+ * @deprecated use {@link #getLightStyleUrl(int)} instead.
*/
- public static final String LIGHT = "mapbox://styles/mapbox/light-v8";
+ @Deprecated
+ public static final String LIGHT = "mapbox://styles/mapbox/light-v9";
+
/**
* Dark: Subtle dark backdrop for data visualizations.
+ *
+ * @deprecated use {@link #getDarkStyleUrl(int)} (int)} instead.
*/
- public static final String DARK = "mapbox://styles/mapbox/dark-v8";
+ @Deprecated
+ public static final String DARK = "mapbox://styles/mapbox/dark-v9";
+
/**
* Satellite: A beautiful global satellite and aerial imagery layer.
+ *
+ * @deprecated use {@link #getSatelliteStyleUrl(int)} instead.
*/
- public static final String SATELLITE = "mapbox://styles/mapbox/satellite-v8";
+ @Deprecated
+ public static final String SATELLITE = "mapbox://styles/mapbox/satellite-v9";
/**
* Satellite Streets: Global satellite and aerial imagery with unobtrusive labels.
+ *
+ * @deprecated use {@link #getSatelliteStreetsStyleUrl(int)} (int)} instead.
*/
- public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-hybrid-v8";
-
+ @Deprecated
+ public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v9";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
index 10ab7a5bbb..5b87e70ef6 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
@@ -16,12 +16,13 @@ import javax.net.ssl.SSLException;
import okhttp3.Call;
import okhttp3.Callback;
+import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
class HTTPRequest implements Callback {
-
+
private static OkHttpClient mClient = new OkHttpClient();
private final String LOG_TAG = HTTPRequest.class.getName();
@@ -46,6 +47,17 @@ class HTTPRequest implements Callback {
mNativePtr = nativePtr;
try {
+ HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
+ final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
+ if (host.equals("mapbox.com") || host.endsWith(".mapbox.com")) {
+ if (httpUrl.querySize() == 0) {
+ resourceUrl = resourceUrl + "?";
+ } else {
+ resourceUrl = resourceUrl + "&";
+ }
+ resourceUrl = resourceUrl + "events=true";
+ }
+
Request.Builder builder = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).addHeader("User-Agent", userAgent);
if (etag.length() > 0) {
builder = builder.addHeader("If-None-Match", etag);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
index 95278ed508..08f18892d2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
@@ -14,11 +14,21 @@ import com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver;
import com.mapzen.android.lost.api.LocationRequest;
import com.mapzen.android.lost.api.LostApiClient;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Manages locational updates. Contains methods to register and unregister location listeners.
+ * <p>
+ * <ul>
+ * <li>You can register a {@link LocationListener} with {@link #addLocationListener(LocationListener)} to receive location updates.</li>
+ * <li> You can unregister a {@link LocationListener} with {@link #removeLocationListener(LocationListener)}.</li>
+ * </ul>
+ * <p/>
+ * <p>
+ * Note: If registering a listener in your Activity.onResume() implementation, you should unregister it in Activity.onPause().
+ * (You won't receive location updates when paused, and this will cut down on unnecessary system overhead).
+ * Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack.
+ * </p>
*/
public class LocationServices implements com.mapzen.android.lost.api.LocationListener {
@@ -30,7 +40,7 @@ public class LocationServices implements com.mapzen.android.lost.api.LocationLis
private LostApiClient locationClient;
private Location lastLocation;
- private List<LocationListener> locationListeners;
+ private CopyOnWriteArrayList<LocationListener> locationListeners;
private boolean isGPSEnabled;
@@ -42,7 +52,7 @@ public class LocationServices implements com.mapzen.android.lost.api.LocationLis
this.context = context;
// Setup location services
locationClient = new LostApiClient.Builder(context).build();
- locationListeners = new ArrayList<>();
+ locationListeners = new CopyOnWriteArrayList<>();
}
/**
@@ -64,8 +74,7 @@ public class LocationServices implements com.mapzen.android.lost.api.LocationLis
* @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled
*/
public void toggleGPS(boolean enableGPS) {
- if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) &&
- (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ if (!areLocationPermissionsGranted()) {
Log.w(TAG, "Location Permissions Not Granted Yet. Try again after requesting.");
return;
}
@@ -123,7 +132,7 @@ public class LocationServices implements com.mapzen.android.lost.api.LocationLis
*/
@Override
public void onLocationChanged(Location location) {
- Log.d(TAG, "onLocationChanged()..." + location);
+// Log.d(TAG, "onLocationChanged()..." + location);
this.lastLocation = location;
// Update Listeners
@@ -166,4 +175,17 @@ public class LocationServices implements com.mapzen.android.lost.api.LocationLis
public boolean removeLocationListener(@NonNull LocationListener locationListener) {
return this.locationListeners.remove(locationListener);
}
+
+ /**
+ * Check status of Location Permissions
+ * @return True if granted to the app, False if not
+ */
+ public boolean areLocationPermissionsGranted() {
+ if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) &&
+ (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ Log.w(TAG, "Location Permissions Not Granted Yet. Try again after requesting.");
+ return false;
+ }
+ return true;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
index 2fefd805ea..27ecb7520b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
@@ -1,14 +1,19 @@
package com.mapbox.mapboxsdk.maps;
import android.app.Fragment;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
+import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
/**
* Fragment wrapper around a map view.
@@ -44,7 +49,7 @@ public final class MapFragment extends Fragment {
}
/**
- * Creates the fragment view hierachy.
+ * Creates the fragment view hierarchy.
*
* @param inflater Inflater used to inflate content.
* @param container The parent layout for the map fragment.
@@ -54,11 +59,67 @@ public final class MapFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- MapboxMapOptions options = getArguments().getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS);
+ MapboxMapOptions options = null;
+
+ // Get bundle
+ Bundle bundle = getArguments();
+ if (bundle != null && bundle.containsKey(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS)) {
+ options = bundle.getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS);
+ }
+
+ // Assign an AccessToken if needed
+ if (options == null || options.getAccessToken() == null) {
+ String token = null;
+ if (MapboxAccountManager.getInstance() != null) {
+ token = MapboxAccountManager.getInstance().getAccessToken();
+ } else {
+ token = getToken(inflater.getContext());
+ }
+ if (TextUtils.isEmpty(token)) {
+ throw new InvalidAccessTokenException();
+ }
+ if (options == null) {
+ options = new MapboxMapOptions().accessToken(token);
+ } else {
+ options.accessToken(token);
+ }
+ }
return mMap = new MapView(inflater.getContext(), options);
}
/**
+ * <p>
+ * Returns the Mapbox access token set in the app resources.
+ * </p>
+ * It will first search the application manifest for a {@link MapboxConstants#KEY_META_DATA_MANIFEST}
+ * meta-data value. If not found it will then attempt to load the access token from the
+ * {@code res/raw/token.txt} development file.
+ *
+ * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}.
+ * @return The Mapbox access token or null if not found.
+ * @see MapboxConstants#KEY_META_DATA_MANIFEST
+ *
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
+ */
+ @Deprecated
+ private String getToken(@NonNull Context context) {
+ try {
+ // read out AndroidManifest
+ PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ String token = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_MANIFEST);
+ if (token == null || token.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+ return token;
+ } catch (Exception e) {
+ // use fallback on string resource, used for development
+ int tokenResId = context.getResources().getIdentifier("mapbox_access_token", "string", context.getPackageName());
+ return tokenResId != 0 ? context.getString(tokenResId) : null;
+ }
+ }
+
+ /**
* Called when the fragment view hierarchy is created.
*
* @param view The content view of the fragment
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 38dd4bccb4..b34b947a2a 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
@@ -10,15 +10,15 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
+import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -58,12 +58,14 @@ import android.widget.ZoomButtonsController;
import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
+import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -73,15 +75,17 @@ import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
-import com.mapbox.mapboxsdk.exceptions.TelemetryServiceNotConfiguredException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.layers.CustomLayer;
+import com.mapbox.mapboxsdk.location.LocationListener;
+import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
-import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.telemetry.MapboxEvent;
import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
+import com.mapbox.mapboxsdk.utils.ColorUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -106,19 +110,25 @@ import java.util.concurrent.CopyOnWriteArrayList;
* </p>
* <strong>Warning:</strong> Please note that you are responsible for getting permission to use the map data,
* and for ensuring your use adheres to the relevant terms of use.
- *
- * @see MapView#setAccessToken(String)
*/
public class MapView extends FrameLayout {
private MapboxMap mMapboxMap;
+ private boolean mInitialLoad;
+ private boolean mDestroyed;
+
private List<Icon> mIcons;
+ private int mAverageIconHeight;
+ private int mAverageIconWidth;
private NativeMapView mNativeMapView;
+ private boolean mHasSurface = false;
+
private CompassView mCompassView;
private ImageView mLogoView;
private ImageView mAttributionsView;
- private UserLocationView mUserLocationView;
+ private MyLocationView mMyLocationView;
+ private LocationListener mMyLocationListener;
private CopyOnWriteArrayList<OnMapChangedListener> mOnMapChangedListener;
private ZoomButtonsController mZoomButtonsController;
@@ -140,11 +150,9 @@ public class MapView extends FrameLayout {
private int mContentPaddingRight;
private int mContentPaddingBottom;
- private String mStyleUrl;
+ private StyleInitializer mStyleInitializer;
private List<OnMapReadyCallback> mOnMapReadyCallbackList;
- private boolean mInitialLoad;
- private boolean mDestroyed;
@UiThread
public MapView(@NonNull Context context) {
@@ -176,6 +184,7 @@ public class MapView extends FrameLayout {
mOnMapChangedListener = new CopyOnWriteArrayList<>();
mMapboxMap = new MapboxMap(this);
mIcons = new ArrayList<>();
+ mStyleInitializer = new StyleInitializer(context);
View view = LayoutInflater.from(context).inflate(R.layout.mapview_internal, this);
if (!isInEditMode()) {
@@ -215,8 +224,8 @@ public class MapView extends FrameLayout {
// Connectivity
onConnectivityChanged(isConnected());
- mUserLocationView = (UserLocationView) view.findViewById(R.id.userLocationView);
- mUserLocationView.setMapboxMap(mMapboxMap);
+ mMyLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
+ mMyLocationView.setMapboxMap(mMapboxMap);
mCompassView = (CompassView) view.findViewById(R.id.compassView);
mCompassView.setMapboxMap(mMapboxMap);
@@ -245,24 +254,45 @@ public class MapView extends FrameLayout {
mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
}
- String accessToken = options.getAccessToken();
- if (!TextUtils.isEmpty(accessToken)) {
- mMapboxMap.setAccessToken(accessToken);
+ String accessToken = null;
+ if (MapboxAccountManager.getInstance() != null) {
+ accessToken = MapboxAccountManager.getInstance().getAccessToken();
+ } else {
+ accessToken = options.getAccessToken();
}
String style = options.getStyle();
- if (!TextUtils.isEmpty(style)) {
- mMapboxMap.setStyleUrl(style);
+ if (!TextUtils.isEmpty(accessToken)) {
+ mMapboxMap.setAccessToken(accessToken);
+ if (style != null) {
+ setStyleUrl(style);
+ }
+ } else {
+ mStyleInitializer.setStyle(style, true);
}
+ // MyLocationView
+ MyLocationViewSettings myLocationViewSettings = mMapboxMap.getMyLocationViewSettings();
+ myLocationViewSettings.setForegroundDrawable(options.getMyLocationForegroundDrawable(), options.getMyLocationForegroundBearingDrawable());
+ myLocationViewSettings.setForegroundTintColor(options.getMyLocationForegroundTintColor());
+ myLocationViewSettings.setBackgroundDrawable(options.getMyLocationBackgroundDrawable(), options.getMyLocationBackgroundPadding());
+ myLocationViewSettings.setBackgroundTintColor(options.getMyLocationBackgroundTintColor());
+ myLocationViewSettings.setAccuracyAlpha(options.getMyLocationAccuracyAlpha());
+ myLocationViewSettings.setAccuracyTintColor(options.getMyLocationAccuracyTintColor());
mMapboxMap.setMyLocationEnabled(options.getLocationEnabled());
// Enable gestures
UiSettings uiSettings = mMapboxMap.getUiSettings();
uiSettings.setZoomGesturesEnabled(options.getZoomGesturesEnabled());
+ uiSettings.setZoomGestureChangeAllowed(options.getZoomGesturesEnabled());
uiSettings.setScrollGesturesEnabled(options.getScrollGesturesEnabled());
+ uiSettings.setScrollGestureChangeAllowed(options.getScrollGesturesEnabled());
uiSettings.setRotateGesturesEnabled(options.getRotateGesturesEnabled());
+ uiSettings.setRotateGestureChangeAllowed(options.getRotateGesturesEnabled());
uiSettings.setTiltGesturesEnabled(options.getTiltGesturesEnabled());
+ uiSettings.setTiltGestureChangeAllowed(options.getTiltGesturesEnabled());
+
+ // Ui Controls
uiSettings.setZoomControlsEnabled(options.getZoomControlsEnabled());
// Zoom
@@ -303,6 +333,10 @@ public class MapView extends FrameLayout {
int seventySixDp = (int) resources.getDimension(R.dimen.seventy_six_dp);
uiSettings.setAttributionMargins(seventySixDp, sevenDp, sevenDp, sevenDp);
}
+
+ int attributionTintColor = options.getAttributionTintColor();
+ uiSettings.setAttributionTintColor(attributionTintColor != -1 ?
+ attributionTintColor : ColorUtils.getPrimaryColor(getContext()));
}
//
@@ -323,7 +357,7 @@ public class MapView extends FrameLayout {
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
// Force a check for an access token
- validateAccessToken(getAccessToken());
+ MapboxAccountManager.validateAccessToken(getAccessToken());
if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
@@ -335,9 +369,13 @@ public class MapView extends FrameLayout {
UiSettings uiSettings = mMapboxMap.getUiSettings();
uiSettings.setZoomGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED));
+ uiSettings.setZoomGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED_CHANGE));
uiSettings.setScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED));
+ uiSettings.setScrollGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE));
uiSettings.setRotateGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED));
+ uiSettings.setRotateGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE));
uiSettings.setTiltGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED));
+ uiSettings.setTiltGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE));
uiSettings.setZoomControlsEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED));
// Compass
@@ -366,9 +404,6 @@ public class MapView extends FrameLayout {
mMapboxMap.setDebugActive(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE));
mMapboxMap.setStyleUrl(savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL));
- setAccessToken(savedInstanceState.getString(MapboxConstants.STATE_ACCESS_TOKEN));
- mNativeMapView.setDefaultTransitionDuration(
- savedInstanceState.getLong(MapboxConstants.STATE_DEFAULT_TRANSITION_DURATION));
// User location
try {
@@ -384,10 +419,8 @@ public class MapView extends FrameLayout {
//noinspection ResourceType
trackingSettings.setMyBearingTrackingMode(savedInstanceState.getInt(MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE));
} else if (savedInstanceState == null) {
- // Force a check for Telemetry
- validateTelemetryServiceConfigured();
-
// Start Telemetry (authorization determined in initial MapboxEventManager constructor)
+ Log.i(MapView.class.getCanonicalName(), "MapView start Telemetry...");
MapboxEventManager eventManager = MapboxEventManager.getMapboxEventManager();
eventManager.initialize(getContext(), getAccessToken());
}
@@ -400,21 +433,21 @@ public class MapView extends FrameLayout {
addOnMapChangedListener(new OnMapChangedListener() {
@Override
public void onMapChanged(@MapChange int change) {
- if (change == DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ if (change == WILL_START_RENDERING_MAP && mInitialLoad) {
+ mInitialLoad = false;
reloadIcons();
reloadMarkers();
adjustTopOffsetPixels();
- if (mInitialLoad) {
- mInitialLoad = false;
- if (mOnMapReadyCallbackList.size() > 0) {
- Iterator<OnMapReadyCallback> iterator = mOnMapReadyCallbackList.iterator();
- while (iterator.hasNext()) {
- OnMapReadyCallback callback = iterator.next();
- callback.onMapReady(mMapboxMap);
- iterator.remove();
- }
+ if (mOnMapReadyCallbackList.size() > 0) {
+ Iterator<OnMapReadyCallback> iterator = mOnMapReadyCallbackList.iterator();
+ while (iterator.hasNext()) {
+ OnMapReadyCallback callback = iterator.next();
+ callback.onMapReady(mMapboxMap);
+ iterator.remove();
}
}
+ } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
+ mMapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation();
}
}
});
@@ -440,9 +473,7 @@ public class MapView extends FrameLayout {
outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, mMapboxMap.getCameraPosition());
outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, mMapboxMap.isDebugActive());
- outState.putString(MapboxConstants.STATE_STYLE_URL, mStyleUrl);
- outState.putString(MapboxConstants.STATE_ACCESS_TOKEN, mMapboxMap.getAccessToken());
- outState.putLong(MapboxConstants.STATE_DEFAULT_TRANSITION_DURATION, mNativeMapView.getDefaultTransitionDuration());
+ outState.putString(MapboxConstants.STATE_STYLE_URL, mStyleInitializer.getStyle());
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, mMapboxMap.isMyLocationEnabled());
// TrackingSettings
@@ -453,9 +484,13 @@ public class MapView extends FrameLayout {
// UiSettings
UiSettings uiSettings = mMapboxMap.getUiSettings();
outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, uiSettings.isZoomGesturesEnabled());
+ outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED_CHANGE, uiSettings.isZoomGestureChangeAllowed());
outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, uiSettings.isScrollGesturesEnabled());
+ outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE, uiSettings.isScrollGestureChangeAllowed());
outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, uiSettings.isRotateGesturesEnabled());
+ outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE, uiSettings.isRotateGestureChangeAllowed());
outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, uiSettings.isTiltGesturesEnabled());
+ outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE, uiSettings.isTiltGestureChangeAllowed());
outState.putBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED, uiSettings.isZoomControlsEnabled());
// UiSettings - Compass
@@ -505,8 +540,7 @@ public class MapView extends FrameLayout {
getContext().unregisterReceiver(mConnectivityReceiver);
mConnectivityReceiver = null;
- mUserLocationView.onPause();
- mNativeMapView.pause();
+ mMyLocationView.onPause();
}
/**
@@ -518,13 +552,12 @@ public class MapView extends FrameLayout {
mConnectivityReceiver = new ConnectivityReceiver();
getContext().registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
- mNativeMapView.resume();
mNativeMapView.update();
- mUserLocationView.onResume();
+ mMyLocationView.onResume();
- if (mStyleUrl == null) {
+ if (mStyleInitializer.isDefaultStyle()) {
// user has failed to supply a style url
- setStyleUrl(Style.MAPBOX_STREETS);
+ setStyleUrl(mStyleInitializer.getStyle());
}
}
@@ -567,20 +600,18 @@ public class MapView extends FrameLayout {
return mNativeMapView.getPitch();
}
- void setTilt(Double pitch, @Nullable Long duration) {
- long actualDuration = 0;
- if (duration != null) {
- actualDuration = duration;
- }
- mNativeMapView.setPitch(pitch, actualDuration);
+ void setTilt(Double pitch) {
+ mMyLocationView.setTilt(pitch);
+ mNativeMapView.setPitch(pitch, 0);
}
+
//
// Direction
//
double getDirection() {
- if(mDestroyed){
+ if (mDestroyed) {
return 0;
}
@@ -641,6 +672,14 @@ public class MapView extends FrameLayout {
return mContentPaddingBottom;
}
+ int getContentWidth(){
+ return getWidth() - mContentPaddingLeft - mContentPaddingRight;
+ }
+
+ int getContentHeight(){
+ return getHeight() - mContentPaddingBottom - mContentPaddingTop;
+ }
+
//
// Zoom
//
@@ -744,7 +783,7 @@ public class MapView extends FrameLayout {
* <li>{@code asset://...}:
* reads the style from the APK {@code assets/} directory.
* This is used to load a style bundled with your app.</li>
- * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
+ * <li>{@code null}: loads the default {@link Style#getMapboxStreetsUrl(int)} style.</li>
* </ul>
* <p>
* This method is asynchronous and will return immediately before the style finishes loading.
@@ -760,7 +799,7 @@ public class MapView extends FrameLayout {
if (mDestroyed) {
return;
}
- mStyleUrl = url;
+ mStyleInitializer.setStyle(url);
mNativeMapView.setStyleUrl(url);
}
@@ -794,7 +833,7 @@ public class MapView extends FrameLayout {
@UiThread
@NonNull
public String getStyleUrl() {
- return mStyleUrl;
+ return mStyleInitializer.getStyle();
}
//
@@ -803,16 +842,21 @@ public class MapView extends FrameLayout {
/**
* <p>
- * Sets the current Mapbox access token used to load map styles and tiles.
+ * DEPRECATED @see MapboxAccountManager#start(String)
* </p>
* <p>
+ * <p>
+ * Sets the current Mapbox access token used to load map styles and tiles.
+ * <p>
* You must set a valid access token before you call {@link MapView#onCreate(Bundle)}
* or an exception will be thrown.
* </p>
*
* @param accessToken Your public Mapbox access token.
* @see MapView#onCreate(Bundle)
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
*/
+ @Deprecated
@UiThread
public void setAccessToken(@NonNull String accessToken) {
if (mDestroyed) {
@@ -822,15 +866,22 @@ public class MapView extends FrameLayout {
if (!TextUtils.isEmpty(accessToken)) {
accessToken = accessToken.trim();
}
- validateAccessToken(accessToken);
+ MapboxAccountManager.validateAccessToken(accessToken);
mNativeMapView.setAccessToken(accessToken);
}
/**
+ * <p>
+ * DEPRECATED @see MapboxAccountManager#getAccessToken()
+ * </p>
+ * <p/>
* Returns the current Mapbox access token used to load map styles and tiles.
+ * </p>
*
* @return The current Mapbox access token.
+ * @deprecated As of release 4.1.0, replaced by {@link MapboxAccountManager#getAccessToken()}
*/
+ @Deprecated
@UiThread
@Nullable
public String getAccessToken() {
@@ -840,31 +891,6 @@ public class MapView extends FrameLayout {
return mNativeMapView.getAccessToken();
}
- // Checks if the given token is valid
- private void validateAccessToken(String accessToken) {
- if (TextUtils.isEmpty(accessToken) || (!accessToken.startsWith("pk.") && !accessToken.startsWith("sk."))) {
- throw new InvalidAccessTokenException();
- }
- }
-
- // Checks that TelemetryService has been configured by developer
- private void validateTelemetryServiceConfigured() {
- try {
- // Check Implementing app's AndroidManifest.xml
- PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), PackageManager.GET_SERVICES);
- if (packageInfo.services != null) {
- for (ServiceInfo service : packageInfo.services) {
- if (TextUtils.equals("com.mapbox.mapboxsdk.telemetry.TelemetryService", service.name)) {
- return;
- }
- }
- }
- } catch (Exception e) {
- Log.w(MapboxConstants.TAG, "Error checking for Telemetry Service Config: " + e);
- }
- throw new TelemetryServiceNotConfiguredException();
- }
-
//
// Projection
//
@@ -873,22 +899,17 @@ public class MapView extends FrameLayout {
if (mDestroyed) {
return new LatLng();
}
- float x = point.x;
- float y = point.y;
-
- return mNativeMapView.latLngForPixel(new PointF(x / mScreenDensity, y / mScreenDensity));
+ point.set(point.x / mScreenDensity, point.y / mScreenDensity);
+ return mNativeMapView.latLngForPixel(point);
}
PointF toScreenLocation(@NonNull LatLng location) {
- if (mDestroyed) {
+ if (mDestroyed || location == null) {
return new PointF();
}
- PointF point = mNativeMapView.pixelForLatLng(location);
-
- float x = point.x * mScreenDensity;
- float y = point.y * mScreenDensity;
-
- return new PointF(x, y);
+ PointF pointF = mNativeMapView.pixelForLatLng(location);
+ pointF.set(pointF.x * mScreenDensity, pointF.y * mScreenDensity);
+ return pointF;
}
//
@@ -897,10 +918,24 @@ public class MapView extends FrameLayout {
Icon loadIconForMarker(Marker marker) {
Icon icon = marker.getIcon();
+
+ // calculating average before adding
+ int iconSize = mIcons.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(getContext()).defaultMarker();
+ Bitmap bitmap = icon.getBitmap();
+ mAverageIconHeight = mAverageIconHeight + (bitmap.getHeight() / 2 - mAverageIconHeight) / iconSize;
+ mAverageIconWidth = mAverageIconHeight + (bitmap.getWidth() - mAverageIconHeight) / iconSize;
marker.setIcon(icon);
+ } else {
+ Bitmap bitmap = icon.getBitmap();
+ mAverageIconHeight = mAverageIconHeight + (bitmap.getHeight() - mAverageIconHeight) / iconSize;
+ mAverageIconWidth = mAverageIconHeight + (bitmap.getWidth() - mAverageIconHeight) / iconSize;
}
+
if (!mIcons.contains(icon)) {
mIcons.add(icon);
loadIcon(icon);
@@ -930,7 +965,6 @@ public class MapView extends FrameLayout {
density = DisplayMetrics.DENSITY_DEFAULT;
}
float scale = density / DisplayMetrics.DENSITY_DEFAULT;
-
mNativeMapView.addAnnotationIcon(
id,
bitmap.getWidth(),
@@ -987,6 +1021,9 @@ public class MapView extends FrameLayout {
}
long addMarker(@NonNull Marker marker) {
+ if(mDestroyed){
+ return 0l;
+ }
return mNativeMapView.addMarker(marker);
}
@@ -1039,16 +1076,11 @@ public class MapView extends FrameLayout {
mNativeMapView.removeAnnotations(ids);
}
- private List<Marker> getMarkersInBounds(@NonNull LatLngBounds bbox) {
- if (mDestroyed) {
+ List<Marker> getMarkersInBounds(@NonNull LatLngBounds bbox) {
+ if (mDestroyed || bbox == null) {
return new ArrayList<>();
}
- if (bbox == null) {
- Log.w(MapboxConstants.TAG, "bbox was null, so just returning null");
- return null;
- }
-
// TODO: filter in JNI using C++ parameter to getAnnotationsInBounds
long[] ids = mNativeMapView.getAnnotationsInBounds(bbox);
@@ -1070,10 +1102,35 @@ public class MapView extends FrameLayout {
return new ArrayList<>(annotations);
}
+ public List<MarkerView> getMarkerViewsInBounds(@NonNull LatLngBounds bbox) {
+ if (mDestroyed || bbox == null) {
+ return new ArrayList<>();
+ }
+
+ // TODO: filter in JNI using C++ parameter to getAnnotationsInBounds
+ long[] ids = mNativeMapView.getAnnotationsInBounds(bbox);
+
+ List<Long> idsList = new ArrayList<>(ids.length);
+ for (int i = 0; i < ids.length; i++) {
+ idsList.add(ids[i]);
+ }
+
+ List<MarkerView> annotations = new ArrayList<>(ids.length);
+ List<Annotation> annotationList = mMapboxMap.getAnnotations();
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
+ annotations.add((MarkerView) annotation);
+ }
+ }
+
+ return new ArrayList<>(annotations);
+ }
+
+
int getTopOffsetPixelsForIcon(Icon icon) {
- // This method will dead lock if map paused. Causes a freeze if you add a marker in an
- // activity's onCreate()
- if (mDestroyed || mNativeMapView.isPaused()) {
+ if (mDestroyed) {
return 0;
}
@@ -1086,18 +1143,28 @@ public class MapView extends FrameLayout {
return;
}
- if (left == mContentPaddingLeft && top == mContentPaddingTop && right == mContentPaddingRight && bottom == mContentPaddingBottom) {
- return;
- }
+// if (left == mContentPaddingLeft && top == mContentPaddingTop && right == mContentPaddingRight && bottom == mContentPaddingBottom) {
+// return;
+// }
mContentPaddingLeft = left;
mContentPaddingTop = top;
mContentPaddingRight = right;
mContentPaddingBottom = bottom;
+ int[] userLocationViewPadding = mMapboxMap.getMyLocationViewSettings().getPadding();
+ left += userLocationViewPadding[0];
+ top += userLocationViewPadding[1];
+ right += userLocationViewPadding[2];
+ bottom += userLocationViewPadding[3];
+
mNativeMapView.setContentPadding(top / mScreenDensity, left / mScreenDensity, bottom / mScreenDensity, right / mScreenDensity);
}
+ public void invalidateContentPadding() {
+ setContentPadding(mContentPaddingLeft, mContentPaddingTop, mContentPaddingRight, mContentPaddingBottom);
+ }
+
double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) double latitude) {
if (mDestroyed) {
return 0;
@@ -1118,7 +1185,7 @@ public class MapView extends FrameLayout {
mNativeMapView.jumpTo(bearing, center, pitch, zoom);
}
- void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
+ void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
if (mDestroyed) {
return;
}
@@ -1139,7 +1206,7 @@ public class MapView extends FrameLayout {
});
}
- mNativeMapView.easeTo(bearing, center, duration, pitch, zoom);
+ mNativeMapView.easeTo(bearing, center, duration, pitch, zoom, easingInterpolator);
}
void flyTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
@@ -1220,11 +1287,15 @@ public class MapView extends FrameLayout {
return;
}
- if (mDestroyed || mNativeMapView.isPaused()) {
+ if (mDestroyed) {
+ return;
+ }
+
+ if (!mHasSurface) {
return;
}
- mNativeMapView.renderSync();
+ mNativeMapView.render();
}
@Override
@@ -1250,6 +1321,10 @@ public class MapView extends FrameLayout {
private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
private Surface mSurface;
+ private View mViewHolder;
+
+ private static final int VIEW_MARKERS_POOL_SIZE = 20;
+
// Called when the native surface texture has been created
// Must do all EGL/GL ES initialization here
@@ -1257,12 +1332,15 @@ public class MapView extends FrameLayout {
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mNativeMapView.createSurface(mSurface = new Surface(surface));
mNativeMapView.resizeFramebuffer(width, height);
+ mHasSurface = true;
}
// Called when the native surface texture has been destroyed
// Must do all EGL/GL ES destruction here
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ mHasSurface = false;
+
if (mNativeMapView != null) {
mNativeMapView.destroySurface();
}
@@ -1274,7 +1352,7 @@ public class MapView extends FrameLayout {
// Must handle window resizing here.
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- if(mDestroyed){
+ if (mDestroyed) {
return;
}
@@ -1285,12 +1363,14 @@ public class MapView extends FrameLayout {
// Must sync with UI here
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- if(mDestroyed){
+ if (mDestroyed) {
return;
}
mCompassView.update(getDirection());
- mUserLocationView.update();
+ mMyLocationView.update();
+ mMapboxMap.getMarkerViewManager().update();
+
for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) {
infoWindow.update();
}
@@ -1432,7 +1512,8 @@ public class MapView extends FrameLayout {
case MotionEvent.ACTION_POINTER_DOWN:
// Second pointer down
- mTwoTap = event.getPointerCount() == 2;
+ mTwoTap = event.getPointerCount() == 2
+ && mMapboxMap.getUiSettings().isZoomGesturesEnabled();
if (mTwoTap) {
// Confirmed 2nd Finger Down
trackGestureEvent(MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY());
@@ -1517,8 +1598,7 @@ public class MapView extends FrameLayout {
zoom(true, e.getX(), e.getY());
} else {
// Zoom in on user location view
- PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
- zoom(true, centerPoint.x, centerPoint.y);
+ zoom(true, mMyLocationView.getCenterX(), mMyLocationView.getCenterY());
}
break;
}
@@ -1540,17 +1620,15 @@ public class MapView extends FrameLayout {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
- // Open / Close InfoWindow
- PointF tapPoint = new PointF(e.getX(), e.getY());
-
List<Marker> selectedMarkers = mMapboxMap.getSelectedMarkers();
- final float toleranceSides = 15 * mScreenDensity;
- final float toleranceTop = 20 * mScreenDensity;
- final float toleranceBottom = 5 * mScreenDensity;
-
- RectF tapRect = new RectF(tapPoint.x - toleranceSides, tapPoint.y + toleranceTop,
- tapPoint.x + toleranceSides, tapPoint.y - toleranceBottom);
+ PointF tapPoint = new PointF(e.getX(), e.getY());
+ float toleranceSides = 4 * mScreenDensity;
+ float toleranceTopBottom = 10 * mScreenDensity;
+ RectF tapRect = new RectF(tapPoint.x - mAverageIconWidth / 2 - toleranceSides,
+ tapPoint.y - mAverageIconHeight / 2 - toleranceTopBottom,
+ tapPoint.x + mAverageIconWidth / 2 + toleranceSides,
+ tapPoint.y + mAverageIconHeight / 2 + toleranceTopBottom);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(fromScreenLocation(new PointF(tapRect.left, tapRect.bottom)));
@@ -1585,7 +1663,10 @@ public class MapView extends FrameLayout {
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
if (selectedMarkers.isEmpty() || !selectedMarkers.contains(annotation)) {
- mMapboxMap.selectMarker((Marker) annotation);
+ // only handle click if no marker view is available
+ if (!(annotation instanceof MarkerView)) {
+ mMapboxMap.selectMarker((Marker) annotation);
+ }
}
break;
}
@@ -1625,9 +1706,7 @@ public class MapView extends FrameLayout {
}
// reset tracking modes if gesture occurs
- if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
- resetTrackingModes();
- }
+ resetTrackingModesIfRequired();
// Fling the map
float ease = 0.25f;
@@ -1663,10 +1742,9 @@ public class MapView extends FrameLayout {
return false;
}
- if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
- // reset tracking modes if gesture occurs
- resetTrackingModes();
- }
+ // reset tracking modes if gesture occurs
+ resetTrackingModesIfRequired();
+
// Cancel any animation
mNativeMapView.cancelTransitions();
@@ -1695,10 +1773,8 @@ public class MapView extends FrameLayout {
return false;
}
- if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
- // reset tracking modes if gesture occurs
- resetTrackingModes();
- }
+ // reset tracking modes if gesture occurs
+ resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY());
@@ -1758,8 +1834,9 @@ public class MapView extends FrameLayout {
mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity);
} else {
// around user location view
- PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
- mNativeMapView.scaleBy(detector.getScaleFactor(), centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity);
+ float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2;
+ float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2;
+ mNativeMapView.scaleBy(detector.getScaleFactor(), x / mScreenDensity, y / mScreenDensity);
}
}
return true;
@@ -1780,10 +1857,8 @@ public class MapView extends FrameLayout {
return false;
}
- if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
- // reset tracking modes if gesture occurs
- resetTrackingModes();
- }
+ // reset tracking modes if gesture occurs
+ resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY());
@@ -1840,8 +1915,9 @@ public class MapView extends FrameLayout {
detector.getFocusY() / mScreenDensity);
} else {
// around center userlocation
- PointF centerPoint = mUserLocationView.getMarkerScreenPoint();
- mNativeMapView.setBearing(bearing, centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity);
+ float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2;
+ float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2;
+ mNativeMapView.setBearing(bearing, x / mScreenDensity, y / mScreenDensity);
}
return true;
}
@@ -1861,10 +1937,8 @@ public class MapView extends FrameLayout {
return false;
}
- if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
- // reset tracking modes if gesture occurs
- resetTrackingModes();
- }
+ // reset tracking modes if gesture occurs
+ resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY());
@@ -1912,14 +1986,14 @@ public class MapView extends FrameLayout {
pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch));
// Tilt the map
- setTilt(pitch, null);
+ mMapboxMap.setTilt(pitch);
return true;
}
}
// This class handles input events from the zoom control buttons
-// Zoom controls allow single touch only devices to zoom in and out
+ // Zoom controls allow single touch only devices to zoom in and out
private class OnZoomListener implements ZoomButtonsController.OnZoomListener {
// Not used
@@ -2269,7 +2343,6 @@ public class MapView extends FrameLayout {
* @param listener The callback that's invoked on every frame rendered to the map view.
* @see MapView#removeOnMapChangedListener(OnMapChangedListener)
*/
- @UiThread
public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
mOnMapChangedListener.add(listener);
@@ -2282,7 +2355,6 @@ public class MapView extends FrameLayout {
* @param listener The previously added callback to remove.
* @see MapView#addOnMapChangedListener(OnMapChangedListener)
*/
- @UiThread
public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
mOnMapChangedListener.remove(listener);
@@ -2308,22 +2380,35 @@ public class MapView extends FrameLayout {
//
void setMyLocationEnabled(boolean enabled) {
- mUserLocationView.setEnabled(enabled);
+ mMyLocationView.setEnabled(enabled);
}
Location getMyLocation() {
- return mUserLocationView.getLocation();
+ return mMyLocationView.getLocation();
}
- void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) {
- mUserLocationView.setOnMyLocationChangeListener(listener);
+ void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) {
+ if (listener != null) {
+ mMyLocationListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (listener != null) {
+ listener.onMyLocationChange(location);
+ }
+ }
+ };
+ LocationServices.getLocationServices(getContext()).addLocationListener(mMyLocationListener);
+ } else {
+ LocationServices.getLocationServices(getContext()).removeLocationListener(mMyLocationListener);
+ mMyLocationListener = null;
+ }
}
void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && !mMapboxMap.isMyLocationEnabled()) {
mMapboxMap.setMyLocationEnabled(true);
}
- mUserLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
+ mMyLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
MapboxMap.OnMyLocationTrackingModeChangeListener listener = mMapboxMap.getOnMyLocationTrackingModeChangeListener();
if (listener != null) {
listener.onMyLocationTrackingModeChange(myLocationTrackingMode);
@@ -2334,7 +2419,7 @@ public class MapView extends FrameLayout {
if (myBearingTrackingMode != MyBearingTracking.NONE && !mMapboxMap.isMyLocationEnabled()) {
mMapboxMap.setMyLocationEnabled(true);
}
- mUserLocationView.setMyBearingTrackingMode(myBearingTrackingMode);
+ mMyLocationView.setMyBearingTrackingMode(myBearingTrackingMode);
MapboxMap.OnMyBearingTrackingModeChangeListener listener = mMapboxMap.getOnMyBearingTrackingModeChangeListener();
if (listener != null) {
listener.onMyBearingTrackingModeChange(myBearingTrackingMode);
@@ -2346,11 +2431,28 @@ public class MapView extends FrameLayout {
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
- private void resetTrackingModes() {
+ private void resetTrackingModesIfRequired() {
+ TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
+ if (trackingSettings.isDismissLocationTrackingOnGesture()) {
+ resetLocationTrackingMode();
+ }
+ if (trackingSettings.isDismissBearingTrackingOnGesture()) {
+ resetBearingTrackingMode();
+ }
+ }
+
+ private void resetLocationTrackingMode() {
try {
TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
- trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
+ } catch (SecurityException ignore) {
+ // User did not accept location permissions
+ }
+ }
+
+ private void resetBearingTrackingMode() {
+ try {
+ setMyBearingTrackingMode(MyBearingTracking.NONE);
} catch (SecurityException ignore) {
// User did not accept location permissions
}
@@ -2404,6 +2506,13 @@ public class MapView extends FrameLayout {
mAttributionsView.setVisibility(visibility);
}
+ void setAtttibutionTintColor(int tintColor) {
+ ColorUtils.setTintList(mAttributionsView, tintColor);
+ }
+
+ int getAttributionTintColor() {
+ return mMapboxMap.getUiSettings().getAttributionTintColor();
+ }
//
// Custom layer
@@ -2455,6 +2564,26 @@ public class MapView extends FrameLayout {
mMapboxMap = mapboxMap;
}
+ MyLocationView getUserLocationView() {
+ return mMyLocationView;
+ }
+
+ @UiThread
+ void snapshot(@NonNull final MapboxMap.SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
+ TextureView textureView = (TextureView) findViewById(R.id.textureView);
+ final boolean canUseBitmap = bitmap != null && textureView.getWidth() == bitmap.getWidth() && textureView.getHeight() == bitmap.getHeight();
+
+ setDrawingCacheEnabled(true);
+ Bitmap content = Bitmap.createBitmap(getDrawingCache());
+ setDrawingCacheEnabled(false);
+
+ Bitmap output = Bitmap.createBitmap(content.getWidth(), content.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+ canvas.drawBitmap(canUseBitmap ? textureView.getBitmap(bitmap) : textureView.getBitmap(), 0, 0, null);
+ canvas.drawBitmap(content, new Matrix(), null);
+ callback.onSnapshotReady(output);
+ }
+
//
// View utility methods
//
@@ -2494,7 +2623,8 @@ public class MapView extends FrameLayout {
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AttributionAlertDialogStyle);
builder.setTitle(R.string.attributionsDialogTitle);
builder.setAdapter(new ArrayAdapter<>(context, R.layout.attribution_list_item, items), this);
- builder.show();
+ AlertDialog dialog = builder.show();
+ dialog.getWindow().setBackgroundDrawable(new ColorDrawable(mMapView.getAttributionTintColor()));
}
// Called when someone selects an attribution, 'Improve this map' adds location data to the url
@@ -2570,6 +2700,41 @@ public class MapView extends FrameLayout {
}
/**
+ * Class responsible for managing state of Style loading.
+ */
+ static class StyleInitializer {
+
+ private String mStyle;
+ private boolean mDefaultStyle;
+
+ StyleInitializer(@NonNull Context context) {
+ mStyle = Style.getMapboxStreetsUrl(context.getResources().getInteger(R.integer.style_version));
+ mDefaultStyle = true;
+ }
+
+ void setStyle(@NonNull String style) {
+ setStyle(style, false);
+ }
+
+ void setStyle(@NonNull String style, boolean defaultStyle) {
+ if (style == null) {
+ // don't override default style
+ return;
+ }
+ mStyle = style;
+ mDefaultStyle = defaultStyle;
+ }
+
+ public String getStyle() {
+ return mStyle;
+ }
+
+ boolean isDefaultStyle() {
+ return mDefaultStyle;
+ }
+ }
+
+ /**
* Definition of a map change event.
*
* @see MapView.OnMapChangedListener#onMapChanged(int)
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 e1a9cd8cdf..fbe6a31f6a 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
@@ -1,5 +1,7 @@
package com.mapbox.mapboxsdk.maps;
+import android.content.Context;
+import android.graphics.Bitmap;
import android.location.Location;
import android.os.SystemClock;
import android.support.annotation.FloatRange;
@@ -7,16 +9,23 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.util.LongSparseArray;
+import android.support.v4.util.Pools;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup;
+import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.Polyline;
@@ -30,7 +39,10 @@ import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.layers.CustomLayer;
+import com.mapbox.mapboxsdk.location.LocationListener;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
+import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -49,13 +61,18 @@ public class MapboxMap {
private MapView mMapView;
private UiSettings mUiSettings;
private TrackingSettings mTrackingSettings;
+ private MyLocationViewSettings myLocationViewSettings;
private Projection mProjection;
private CameraPosition mCameraPosition;
private boolean mInvalidCameraPosition;
private LongSparseArray<Annotation> mAnnotations;
+
private List<Marker> mSelectedMarkers;
+ private MarkerViewManager mMarkerViewManager;
+
private List<InfoWindow> mInfoWindows;
private MapboxMap.InfoWindowAdapter mInfoWindowAdapter;
+ private Bitmap mViewMarkerBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
private boolean mMyLocationEnabled;
private boolean mAllowConcurrentMultipleInfoWindows;
@@ -85,6 +102,7 @@ public class MapboxMap {
mAnnotations = new LongSparseArray<>();
mSelectedMarkers = new ArrayList<>();
mInfoWindows = new ArrayList<>();
+ mMarkerViewManager = new MarkerViewManager(this, mapView);
}
//
@@ -186,6 +204,20 @@ public class MapboxMap {
}
//
+ // MyLocationViewSettings
+ //
+
+ /**
+ * Gets the settings of the user location for the map.
+ */
+ public MyLocationViewSettings getMyLocationViewSettings() {
+ if (myLocationViewSettings == null) {
+ myLocationViewSettings = new MyLocationViewSettings(mMapView, mMapView.getUserLocationView());
+ }
+ return myLocationViewSettings;
+ }
+
+ //
// Projection
//
@@ -254,10 +286,12 @@ public class MapboxMap {
}
/**
- * Ease the map according to the update with an animation over a specified duration, and calls an optional callback on completion. See CameraUpdateFactory for a set of updates.
- * If getCameraPosition() is called during the animation, it will return the current location of the camera in flight.
+ * Gradually move the camera by the default duration, zoom will not be affected unless specified
+ * within {@link CameraUpdate}. If {@link #getCameraPosition()} is called during the animation,
+ * it will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update) {
@@ -265,11 +299,14 @@ public class MapboxMap {
}
/**
- * Ease the map according to the update with an animation over a specified duration, and calls an optional callback on completion. See CameraUpdateFactory for a set of updates.
- * If getCameraPosition() is called during the animation, it will return the current location of the camera in flight.
+ * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
+ * unless specified within {@link CameraUpdate}. If {@link #getCameraPosition()} is called
+ * during the animation, it will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @param durationMs The duration of the animation in milliseconds. This must be strictly positive, otherwise an IllegalArgumentException will be thrown.
+ * @param durationMs The duration of the animation in milliseconds. This must be strictly
+ * positive, otherwise an IllegalArgumentException will be thrown.
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs) {
@@ -277,17 +314,35 @@ public class MapboxMap {
}
/**
- * Ease the map according to the update with an animation over a specified duration, and calls an optional callback on completion. See CameraUpdateFactory for a set of updates.
- * If getCameraPosition() is called during the animation, it will return the current location of the camera in flight.
+ * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
+ * unless specified within {@link CameraUpdate}. A callback can be used to be notified when
+ * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
+ * will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @param durationMs The duration of the animation in milliseconds. This must be strictly positive, otherwise an IllegalArgumentException will be thrown.
- * @param callback An optional callback to be notified from the main thread when the animation stops. If the animation stops due to its natural completion, the callback will be notified with onFinish(). If the animation stops due to interruption by a later camera movement or a user gesture, onCancel() will be called. The callback should not attempt to move or animate the camera in its cancellation method. If a callback isn't required, leave it as null.
+ * @param durationMs The duration of the animation in milliseconds. This must be strictly
+ * positive, otherwise an IllegalArgumentException will be thrown.
+ * @param callback An optional callback to be notified from the main thread when the animation
+ * stops. If the animation stops due to its natural completion, the callback
+ * will be notified with onFinish(). If the animation stops due to interruption
+ * by a later camera movement or a user gesture, onCancel() will be called.
+ * Do not update or ease the camera from within onCancel().
+ * @see {@link CameraUpdateFactory} for a set of camera updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
+ easeCamera(update, durationMs, true, callback);
+ }
+
+ @UiThread
+ public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) {
+ easeCamera(update, durationMs, easingInterpolator, null);
+ }
+
+ @UiThread
+ public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) {
mCameraPosition = update.getCameraPosition(this);
- mMapView.easeTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, new CancelableCallback() {
+ mMapView.easeTo(mCameraPosition.bearing, mCameraPosition.target, getDurationNano(durationMs), mCameraPosition.tilt, mCameraPosition.zoom, easingInterpolator, new CancelableCallback() {
@Override
public void onCancel() {
if (callback != null) {
@@ -307,12 +362,13 @@ public class MapboxMap {
}
/**
- * Animates the movement of the camera from the current position to the position defined in the update.
- * During the animation, a call to getCameraPosition() returns an intermediate location of the camera.
- * <p/>
- * See CameraUpdateFactory for a set of updates.
+ * Animate the camera to a new location defined within {@link CameraUpdate} using a transition
+ * animation that evokes powered flight. The animation will last the default amount of time.
+ * During the animation, a call to {@link #getCameraPosition()} returns an intermediate location
+ * of the camera in flight.
*
* @param update The change that should be applied to the camera.
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update) {
@@ -320,12 +376,16 @@ public class MapboxMap {
}
/**
- * Animates the movement of the camera from the current position to the position defined in the update and calls an optional callback on completion.
- * See CameraUpdateFactory for a set of updates.
- * During the animation, a call to getCameraPosition() returns an intermediate location of the camera.
+ * Animate the camera to a new location defined within {@link CameraUpdate} using a transition
+ * animation that evokes powered flight. The animation will last the default amount of time. A
+ * callback can be used to be notified when animating the camera stops. During the animation, a
+ * call to {@link #getCameraPosition()} returns an intermediate location of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @param callback The callback to invoke from the main thread when the animation stops. If the animation completes normally, onFinish() is called; otherwise, onCancel() is called. Do not update or animate the camera from within onCancel().
+ * @param callback The callback to invoke from the main thread when the animation stops. If the
+ * animation completes normally, onFinish() is called; otherwise, onCancel() is
+ * called. Do not update or animate the camera from within onCancel().
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
@@ -333,11 +393,15 @@ public class MapboxMap {
}
/**
- * Moves the map according to the update with an animation over a specified duration. See CameraUpdateFactory for a set of updates.
- * If getCameraPosition() is called during the animation, it will return the current location of the camera in flight.
+ * Animate the camera to a new location defined within {@link CameraUpdate} using a transition
+ * animation that evokes powered flight. The animation will last a specified amount of time
+ * given in milliseconds. During the animation, a call to {@link #getCameraPosition()} returns
+ * an intermediate location of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @param durationMs The duration of the animation in milliseconds. This must be strictly positive, otherwise an IllegalArgumentException will be thrown.
+ * @param durationMs The duration of the animation in milliseconds. This must be strictly
+ * positive, otherwise an IllegalArgumentException will be thrown.
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs) {
@@ -345,12 +409,22 @@ public class MapboxMap {
}
/**
- * Moves the map according to the update with an animation over a specified duration, and calls an optional callback on completion. See CameraUpdateFactory for a set of updates.
- * If getCameraPosition() is called during the animation, it will return the current location of the camera in flight.
+ * Animate the camera to a new location defined within {@link CameraUpdate} using a transition
+ * animation that evokes powered flight. The animation will last a specified amount of time
+ * given in milliseconds. A callback can be used to be notified when animating the camera stops.
+ * During the animation, a call to {@link #getCameraPosition()} returns an intermediate location
+ * of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @param durationMs The duration of the animation in milliseconds. This must be strictly positive, otherwise an IllegalArgumentException will be thrown.
- * @param callback An optional callback to be notified from the main thread when the animation stops. If the animation stops due to its natural completion, the callback will be notified with onFinish(). If the animation stops due to interruption by a later camera movement or a user gesture, onCancel() will be called. The callback should not attempt to move or animate the camera in its cancellation method. If a callback isn't required, leave it as null.
+ * @param durationMs The duration of the animation in milliseconds. This must be strictly
+ * positive, otherwise an IllegalArgumentException will be thrown.
+ * @param callback An optional callback to be notified from the main thread when the animation
+ * stops. If the animation stops due to its natural completion, the callback
+ * will be notified with onFinish(). If the animation stops due to interruption
+ * by a later camera movement or a user gesture, onCancel() will be called.
+ * Do not update or animate the camera from within onCancel(). If a callback
+ * isn't required, leave it as null.
+ * @see {@link CameraUpdateFactory} for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
@@ -476,7 +550,7 @@ public class MapboxMap {
* <li>{@code asset://...}:
* reads the style from the APK {@code assets/} directory.
* This is used to load a style bundled with your app.</li>
- * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
+ * <li>{@code null}: loads the default {@link Style#getMapboxStreetsUrl(int)} style.</li>
* </ul>
* <p>
* This method is asynchronous and will return immediately before the style finishes loading.
@@ -506,8 +580,10 @@ public class MapboxMap {
*
* @param style The bundled style. Accepts one of the values from {@link Style}.
* @see Style
+ * @deprecated use {@link #setStyleUrl(String)} instead with versioned url methods from {@link Style}
*/
@UiThread
+ @Deprecated
public void setStyle(@Style.StyleUrl String style) {
setStyleUrl(style);
}
@@ -532,22 +608,34 @@ public class MapboxMap {
/**
* <p>
+ * DEPRECATED @see MapboxAccountManager#start(String)
+ * </p>
+ * <p>
* Sets the current Mapbox access token used to load map styles and tiles.
* </p>
*
* @param accessToken Your public Mapbox access token.
* @see MapView#setAccessToken(String)
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
*/
+ @Deprecated
@UiThread
public void setAccessToken(@NonNull String accessToken) {
mMapView.setAccessToken(accessToken);
}
/**
+ * <p>
+ * DEPRECATED @see MapboxAccountManager#getAccessToken()
+ * </p>
+ * <p>
* Returns the current Mapbox access token used to load map styles and tiles.
+ * </p>
*
* @return The current Mapbox access token.
+ * @deprecated As of release 4.1.0, replaced by {@link MapboxAccountManager#getAccessToken()}
*/
+ @Deprecated
@UiThread
@Nullable
public String getAccessToken() {
@@ -558,6 +646,12 @@ public class MapboxMap {
// Annotations
//
+ void setTilt(double tilt) {
+ mMarkerViewManager.setTilt((float) tilt);
+ mMapView.setTilt(tilt);
+ }
+
+
/**
* <p>
* Adds a marker to this map.
@@ -597,6 +691,27 @@ public class MapboxMap {
/**
* <p>
+ * Adds a marker to this map.
+ * </p>
+ * The marker's icon is rendered on the map at the location {@code Marker.position}.
+ * If {@code Marker.title} is defined, the map shows an info box with the marker's title and snippet.
+ *
+ * @param markerOptions A marker options object that defines how to render the marker.
+ * @return The {@code Marker} that was added to the map.
+ */
+ @UiThread
+ @NonNull
+ public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions) {
+ MarkerView marker = prepareViewMarker(markerOptions);
+ long id = mMapView.addMarker(marker);
+ marker.setMapboxMap(this);
+ marker.setId(id);
+ mAnnotations.put(id, marker);
+ return marker;
+ }
+
+ /**
+ * <p>
* Adds multiple markers to this map.
* </p>
* The marker's icon is rendered on the map at the location {@code Marker.position}.
@@ -607,11 +722,11 @@ public class MapboxMap {
*/
@UiThread
@NonNull
- public List<Marker> addMarkers(@NonNull List<MarkerOptions> markerOptionsList) {
+ public List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList) {
int count = markerOptionsList.size();
List<Marker> markers = new ArrayList<>(count);
if (count > 0) {
- MarkerOptions markerOptions;
+ BaseMarkerOptions markerOptions;
Marker marker;
for (int i = 0; i < count; i++) {
markerOptions = markerOptionsList.get(i);
@@ -693,7 +808,7 @@ public class MapboxMap {
Polyline polyline;
List<Polyline> polylines = new ArrayList<>(count);
- if(count>0) {
+ if (count > 0) {
for (PolylineOptions options : polylineOptionsList) {
polyline = options.getPolyline();
if (!polyline.getPoints().isEmpty()) {
@@ -757,7 +872,7 @@ public class MapboxMap {
Polygon polygon;
List<Polygon> polygons = new ArrayList<>(count);
- if(count>0) {
+ if (count > 0) {
for (PolygonOptions polygonOptions : polygonOptionsList) {
polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
@@ -767,8 +882,8 @@ public class MapboxMap {
long[] ids = mMapView.addPolygons(polygons);
- // if unit tests or polygons correcly added to map
- if(ids==null || ids.length==polygons.size()) {
+ // if unit tests or polygons correctly added to map
+ if (ids == null || ids.length == polygons.size()) {
long id = 0;
for (int i = 0; i < polygons.size(); i++) {
polygon = polygons.get(i);
@@ -834,7 +949,11 @@ public class MapboxMap {
@UiThread
public void removeAnnotation(@NonNull Annotation annotation) {
if (annotation instanceof Marker) {
- ((Marker) annotation).hideInfoWindow();
+ Marker marker = (Marker) annotation;
+ marker.hideInfoWindow();
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ }
}
long id = annotation.getId();
mMapView.removeAnnotation(id);
@@ -864,7 +983,11 @@ public class MapboxMap {
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof Marker) {
- ((Marker) annotation).hideInfoWindow();
+ Marker marker = (Marker) annotation;
+ marker.hideInfoWindow();
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ }
}
ids[i] = annotationList.get(i).getId();
}
@@ -886,7 +1009,11 @@ public class MapboxMap {
ids[i] = mAnnotations.keyAt(i);
annotation = mAnnotations.get(ids[i]);
if (annotation instanceof Marker) {
- ((Marker) annotation).hideInfoWindow();
+ Marker marker = (Marker) annotation;
+ marker.hideInfoWindow();
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ }
}
}
mMapView.removeAnnotations(ids);
@@ -894,11 +1021,18 @@ public class MapboxMap {
}
/**
+ * Removes all markers, polylines, polygons, overlays, etc from the map.
+ */
+ @UiThread
+ public void clear() {
+ removeAnnotations();
+ }
+
+ /**
* Return a annotation based on its id.
*
* @return An annotation with a matched id, null is returned if no match was found.
*/
- @UiThread
@Nullable
public Annotation getAnnotation(long id) {
return mAnnotations.get(id);
@@ -989,8 +1123,7 @@ public class MapboxMap {
@UiThread
public void selectMarker(@NonNull Marker marker) {
if (marker == null) {
- Log.w(MapboxConstants.TAG, "marker was null, so just" +
- " returning");
+ Log.w(MapboxConstants.TAG, "marker was null, so just returning");
return;
}
@@ -1031,6 +1164,10 @@ public class MapboxMap {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
+
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.deselect((MarkerView) marker);
+ }
}
// Removes all selected markers from the list
@@ -1070,6 +1207,22 @@ public class MapboxMap {
return marker;
}
+ private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
+ MarkerView marker = markerViewOptions.getMarker();
+ Icon icon = IconFactory.recreate("markerViewSettings", mViewMarkerBitmap);
+ marker.setIcon(icon);
+ return marker;
+ }
+
+ /**
+ * Get the MarkerViewManager associated to the MapView.
+ *
+ * @return the associated MarkerViewManager
+ */
+ public MarkerViewManager getMarkerViewManager() {
+ return mMarkerViewManager;
+ }
+
//
// InfoWindow
//
@@ -1142,6 +1295,7 @@ public class MapboxMap {
* view’s frame. Otherwise, those properties are inset, excluding part of the
* frame from the viewport. For instance, if the only the top edge is inset, the
* map center is effectively shifted downward.
+ * </p>
*
* @param left The left margin in pixels.
* @param top The top margin in pixels.
@@ -1151,8 +1305,6 @@ public class MapboxMap {
public void setPadding(int left, int top, int right, int bottom) {
mMapView.setContentPadding(left, top, right, bottom);
mUiSettings.invalidate();
-
- moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(mCameraPosition).build()));
}
/**
@@ -1381,8 +1533,10 @@ public class MapboxMap {
*
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationServices#addLocationListener(LocationListener)})}
*/
@UiThread
+ @Deprecated
public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) {
mMapView.setOnMyLocationChangeListener(listener);
}
@@ -1451,6 +1605,14 @@ public class MapboxMap {
return mMapView;
}
+ void setUiSettings(UiSettings uiSettings) {
+ mUiSettings = uiSettings;
+ }
+
+ void setProjection(Projection projection) {
+ mProjection = projection;
+ }
+
//
// Invalidate
//
@@ -1462,6 +1624,27 @@ public class MapboxMap {
mMapView.update();
}
+ /**
+ * Takes a snapshot of the map.
+ *
+ * @param callback Callback method invoked when the snapshot is taken.
+ * @param bitmap A pre-allocated bitmap.
+ */
+ @UiThread
+ public void snapshot(@NonNull SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
+ mMapView.snapshot(callback, bitmap);
+ }
+
+ /**
+ * Takes a snapshot of the map.
+ *
+ * @param callback Callback method invoked when the snapshot is taken.
+ */
+ @UiThread
+ public void snapshot(@NonNull SnapshotReadyCallback callback) {
+ mMapView.snapshot(callback, null);
+ }
+
//
// Interfaces
//
@@ -1624,10 +1807,92 @@ public class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked when an MarkerView will be shown.
+ *
+ * @param <U> the instance type of MarkerView
+ */
+ public static abstract class MarkerViewAdapter<U extends MarkerView> {
+
+ private Context context;
+ private final Class<U> persistentClass;
+ private final Pools.SimplePool<View> mViewReusePool;
+
+ /**
+ * Create an instance of MarkerViewAdapter.
+ *
+ * @param context the context associated to a MapView
+ */
+ @SuppressWarnings("unchecked")
+ public MarkerViewAdapter(Context context) {
+ this.context = context;
+ persistentClass = (Class<U>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+ mViewReusePool = new Pools.SimplePool<>(20);
+ }
+
+ /**
+ * Called when an MarkerView will be added to the MapView.
+ *
+ * @param marker the model representing the MarkerView
+ * @param convertView the reusable view
+ * @param parent the parent ViewGroup of the convertview
+ * @return the View that is adapted to the contents of MarkerView
+ */
+ @Nullable
+ public abstract View getView(@NonNull U marker, @NonNull View convertView, @NonNull ViewGroup parent);
+
+ /**
+ * Returns the generic type of the used MarkerView.
+ *
+ * @return the generic type
+ */
+ public Class<U> getMarkerClass() {
+ return persistentClass;
+ }
+
+ /**
+ * Returns the pool used to store reusable Views.
+ *
+ * @return the pool associated to this adapter
+ */
+ public Pools.SimplePool<View> getViewReusePool() {
+ return mViewReusePool;
+ }
+
+ /**
+ * Returns the context associated to the hosting MapView.
+ *
+ * @return the context used
+ */
+ public Context getContext() {
+ return context;
+ }
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the user clicks on a MarkerView.
+ *
+ * @see MarkerViewManager#setOnMarkerViewClickListener(OnMarkerViewClickListener)
+ */
+ public interface OnMarkerViewClickListener {
+
+ /**
+ * Called when the user clicks on a MarkerView.
+ *
+ * @param marker the MarkerView associated to the clicked View
+ * @param view the clicked View
+ * @param adapter the adapter used to adapt the MarkerView to the View
+ * @return If true the listener has consumed the event and the info window will not be shown
+ */
+ boolean onMarkerClick(@NonNull Marker marker, @NonNull View view, @NonNull MarkerViewAdapter adapter);
+ }
+
+ /**
* Interface definition for a callback to be invoked when the the My Location view changes location.
*
* @see MapboxMap#setOnMyLocationChangeListener(OnMyLocationChangeListener)
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationListener}
*/
+ @Deprecated
public interface OnMyLocationChangeListener {
/**
* Called when the location of the My Location view has changed
@@ -1683,6 +1948,16 @@ public class MapboxMap {
void onFinish();
}
+ /**
+ * Interface definition for a callback to be invoked when the snapshot has been taken.
+ */
+ public interface SnapshotReadyCallback {
+ /**
+ * Invoked when the snapshot has been taken.
+ */
+ void onSnapshotReady(Bitmap snapshot);
+ }
+
private class MapChangeCameraPositionListener implements MapView.OnMapChangedListener {
private static final long UPDATE_RATE_MS = 400;
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 6b7a0db8bd..17593129e7 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
@@ -2,16 +2,22 @@ package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Gravity;
-
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.utils.ColorUtils;
+import java.util.Arrays;
/**
* Defines configuration MapboxMapMapOptions for a MapboxMap. These options can be used when adding a
@@ -40,6 +46,8 @@ public class MapboxMapOptions implements Parcelable {
private int logoGravity = Gravity.BOTTOM | Gravity.START;
private int logoMargins[];
+ @ColorInt
+ private int attributionTintColor = -1;
private boolean attributionEnabled = true;
private int attributionGravity = Gravity.BOTTOM;
private int attributionMargins[];
@@ -53,9 +61,18 @@ public class MapboxMapOptions implements Parcelable {
private boolean zoomGesturesEnabled = true;
private boolean zoomControlsEnabled = false;
- private boolean locationEnabled;
+ private boolean myLocationEnabled;
+ private Drawable myLocationForegroundDrawable;
+ private Drawable myLocationForegroundBearingDrawable;
+ private Drawable myLocationBackgroundDrawable;
+ private int myLocationForegroundTintColor;
+ private int myLocationBackgroundTintColor;
+ private int[] myLocationBackgroundPadding;
+ private int myLocationAccuracyTintColor;
+ private int myLocationAccuracyAlpha;
private String style;
+ @Deprecated
private String accessToken;
/**
@@ -79,6 +96,7 @@ public class MapboxMapOptions implements Parcelable {
attributionEnabled = in.readByte() != 0;
attributionGravity = in.readInt();
attributionMargins = in.createIntArray();
+ attributionTintColor = in.readInt();
minZoom = in.readFloat();
maxZoom = in.readFloat();
@@ -89,7 +107,15 @@ public class MapboxMapOptions implements Parcelable {
zoomControlsEnabled = in.readByte() != 0;
zoomGesturesEnabled = in.readByte() != 0;
- locationEnabled = in.readByte() != 0;
+ myLocationEnabled = in.readByte() != 0;
+ //myLocationForegroundDrawable;
+ //myLocationForegroundBearingDrawable;
+ //myLocationBackgroundDrawable;
+ myLocationForegroundTintColor = in.readInt();
+ myLocationBackgroundTintColor = in.readInt();
+ myLocationBackgroundPadding = in.createIntArray();
+ myLocationAccuracyAlpha = in.readInt();
+ myLocationAccuracyTintColor = in.readInt();
style = in.readString();
accessToken = in.readString();
@@ -137,6 +163,7 @@ public class MapboxMapOptions implements Parcelable {
, (int) (typedArray.getDimension(R.styleable.MapView_logo_margin_right, DIMENSION_SIXTEEN_DP) * screenDensity)
, (int) (typedArray.getDimension(R.styleable.MapView_logo_margin_bottom, DIMENSION_SIXTEEN_DP) * screenDensity)});
+ mapboxMapOptions.attributionTintColor(typedArray.getColor(R.styleable.MapView_attribution_tint, -1));
mapboxMapOptions.attributionEnabled(typedArray.getBoolean(R.styleable.MapView_attribution_enabled, true));
mapboxMapOptions.attributionGravity(typedArray.getInt(R.styleable.MapView_attribution_gravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[]{(int) (typedArray.getDimension(R.styleable.MapView_attribution_margin_left, DIMENSION_SEVENTY_SIX_DP) * screenDensity)
@@ -145,6 +172,32 @@ public class MapboxMapOptions implements Parcelable {
, (int) (typedArray.getDimension(R.styleable.MapView_attribution_margin_bottom, DIMENSION_SEVEN_DP) * screenDensity)});
mapboxMapOptions.locationEnabled(typedArray.getBoolean(R.styleable.MapView_my_location_enabled, false));
+ mapboxMapOptions.myLocationForegroundTintColor(typedArray.getColor(R.styleable.MapView_my_location_foreground_tint, Color.TRANSPARENT));
+ mapboxMapOptions.myLocationBackgroundTintColor(typedArray.getColor(R.styleable.MapView_my_location_background_tint, Color.TRANSPARENT));
+
+ Drawable foregroundDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_foreground);
+ if(foregroundDrawable==null){
+ foregroundDrawable = ContextCompat.getDrawable(context,R.drawable.ic_mylocationview_normal);
+ }
+
+ Drawable foregroundBearingDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_foreground_bearing);
+ if(foregroundBearingDrawable==null){
+ foregroundBearingDrawable = ContextCompat.getDrawable(context,R.drawable.ic_mylocationview_bearing);
+ }
+
+ Drawable backgroundDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_background);
+ if(backgroundDrawable==null){
+ backgroundDrawable = ContextCompat.getDrawable(context, R.drawable.ic_mylocationview_background);
+ }
+
+ mapboxMapOptions.myLocationForegroundDrawables(foregroundDrawable, foregroundBearingDrawable);
+ mapboxMapOptions.myLocationBackgroundDrawable(backgroundDrawable);
+ mapboxMapOptions.myLocationBackgroundPadding(new int[]{(int) (typedArray.getDimension(R.styleable.MapView_my_location_background_left, 0) * screenDensity)
+ , (int) (typedArray.getDimension(R.styleable.MapView_my_location_background_top, 0) * screenDensity)
+ , (int) (typedArray.getDimension(R.styleable.MapView_my_location_background_right, 0) * screenDensity)
+ , (int) (typedArray.getDimension(R.styleable.MapView_my_location_background_bottom, 0) * screenDensity)});
+ mapboxMapOptions.myLocationAccuracyAlpha(typedArray.getInt(R.styleable.MapView_my_location_accuracy_alpha, 100));
+ mapboxMapOptions.myLocationAccuracyTint(typedArray.getColor(R.styleable.MapView_my_location_accuracy_tint, ColorUtils.getPrimaryColor(context)));
} finally {
typedArray.recycle();
}
@@ -163,11 +216,15 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * <p>
+ * DEPRECATED @see MapboxAccountManager#start(String)
+ * </p>
* Specifies the accesstoken associated with a map view.
*
* @param accessToken Token to be used to access the service
* @return This
*/
+ @Deprecated
public MapboxMapOptions accessToken(String accessToken) {
this.accessToken = accessToken;
return this;
@@ -317,6 +374,17 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Specifies the tint color of the attribution for a map view
+ *
+ * @param color integer resembling a color
+ * @return This
+ */
+ public MapboxMapOptions attributionTintColor(@ColorInt int color) {
+ attributionTintColor = color;
+ return this;
+ }
+
+ /**
* Specifies if the rotate gesture is enabled for a map view.
*
* @param enabled True and gesture will be enabled
@@ -378,7 +446,73 @@ public class MapboxMapOptions implements Parcelable {
* @return This
*/
public MapboxMapOptions locationEnabled(boolean locationEnabled) {
- this.locationEnabled = locationEnabled;
+ this.myLocationEnabled = locationEnabled;
+ return this;
+ }
+
+ /**
+ *
+ * @param myLocationForegroundDrawable
+ * @param myLocationBearingDrawable
+ * @return This
+ */
+ public MapboxMapOptions myLocationForegroundDrawables(Drawable myLocationForegroundDrawable, Drawable myLocationBearingDrawable ) {
+ this.myLocationForegroundDrawable = myLocationForegroundDrawable;
+ this.myLocationForegroundBearingDrawable = myLocationBearingDrawable;
+ return this;
+ }
+
+ /**
+ * @param myLocationBackgroundDrawable
+ * @return This
+ */
+ public MapboxMapOptions myLocationBackgroundDrawable(Drawable myLocationBackgroundDrawable) {
+ this.myLocationBackgroundDrawable = myLocationBackgroundDrawable;
+ return this;
+ }
+
+ /**
+ * @param myLocationForegroundTintColor
+ * @return This
+ */
+ public MapboxMapOptions myLocationForegroundTintColor(@ColorInt int myLocationForegroundTintColor) {
+ this.myLocationForegroundTintColor = myLocationForegroundTintColor;
+ return this;
+ }
+
+ /**
+ * @param myLocationBackgroundTintColor
+ * @return This
+ */
+ public MapboxMapOptions myLocationBackgroundTintColor(@ColorInt int myLocationBackgroundTintColor) {
+ this.myLocationBackgroundTintColor = myLocationBackgroundTintColor;
+ return this;
+ }
+
+ /**
+ * @param myLocationBackgroundPadding
+ * @return This
+ */
+ public MapboxMapOptions myLocationBackgroundPadding(int[] myLocationBackgroundPadding) {
+ this.myLocationBackgroundPadding = myLocationBackgroundPadding;
+ return this;
+ }
+
+ /**
+ * @param myLocationAccuracyTintColor
+ * @return This
+ */
+ public MapboxMapOptions myLocationAccuracyTint(@ColorInt int myLocationAccuracyTintColor) {
+ this.myLocationAccuracyTintColor = myLocationAccuracyTintColor;
+ return this;
+ }
+
+ /**
+ * @param alpha
+ * @return This
+ */
+ public MapboxMapOptions myLocationAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) {
+ this.myLocationAccuracyAlpha = alpha;
return this;
}
@@ -464,10 +598,14 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * <p>
+ * DEPRECATED @see MapboxAccountManager#start(String)
+ * </p>
* Get the current configured access token for a map view.
*
* @return Access token to be used.
*/
+ @Deprecated
public String getAccessToken() {
return accessToken;
}
@@ -553,13 +691,74 @@ public class MapboxMapOptions implements Parcelable {
return attributionMargins;
}
+ @ColorInt
+ public int getAttributionTintColor() {
+ return attributionTintColor;
+ }
+
/**
* Get the current configured user location view state for a map view.
*
* @return True and user location will be shown
*/
public boolean getLocationEnabled() {
- return locationEnabled;
+ return myLocationEnabled;
+ }
+
+ /**
+ * @return
+ */
+ public Drawable getMyLocationForegroundDrawable() {
+ return myLocationForegroundDrawable;
+ }
+
+ /**
+ * @return
+ */
+ public Drawable getMyLocationForegroundBearingDrawable() {
+ return myLocationForegroundBearingDrawable;
+ }
+
+ /**
+ * @return
+ */
+ public Drawable getMyLocationBackgroundDrawable() {
+ return myLocationBackgroundDrawable;
+ }
+
+ /**
+ * @return
+ */
+ public int getMyLocationForegroundTintColor() {
+ return myLocationForegroundTintColor;
+ }
+
+ /**
+ * @return
+ */
+ public int getMyLocationBackgroundTintColor() {
+ return myLocationBackgroundTintColor;
+ }
+
+ /**
+ * @return
+ */
+ public int[] getMyLocationBackgroundPadding() {
+ return myLocationBackgroundPadding;
+ }
+
+ /**
+ * @return
+ */
+ public int getMyLocationAccuracyTintColor() {
+ return myLocationAccuracyTintColor;
+ }
+
+ /**
+ * @return
+ */
+ public int getMyLocationAccuracyAlpha() {
+ return myLocationAccuracyAlpha;
}
/**
@@ -603,6 +802,7 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (attributionEnabled ? 1 : 0));
dest.writeInt(attributionGravity);
dest.writeIntArray(attributionMargins);
+ dest.writeInt(attributionTintColor);
dest.writeFloat(minZoom);
dest.writeFloat(maxZoom);
@@ -613,9 +813,94 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (zoomControlsEnabled ? 1 : 0));
dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0));
- dest.writeByte((byte) (locationEnabled ? 1 : 0));
+ dest.writeByte((byte) (myLocationEnabled ? 1 : 0));
+ //myLocationForegroundDrawable;
+ //myLocationForegroundBearingDrawable;
+ //myLocationBackgroundDrawable;
+ dest.writeInt(myLocationForegroundTintColor);
+ dest.writeInt(myLocationBackgroundTintColor);
+ dest.writeIntArray(myLocationBackgroundPadding);
+ dest.writeInt(myLocationAccuracyAlpha);
+ dest.writeInt(myLocationAccuracyTintColor);
dest.writeString(style);
dest.writeString(accessToken);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MapboxMapOptions options = (MapboxMapOptions) o;
+
+ if (debugActive != options.debugActive) return false;
+ if (compassEnabled != options.compassEnabled) return false;
+ if (compassGravity != options.compassGravity) return false;
+ if (logoEnabled != options.logoEnabled) return false;
+ if (logoGravity != options.logoGravity) return false;
+ if (attributionEnabled != options.attributionEnabled) return false;
+ if (attributionGravity != options.attributionGravity) return false;
+ if (Float.compare(options.minZoom, minZoom) != 0) return false;
+ if (Float.compare(options.maxZoom, maxZoom) != 0) return false;
+ if (rotateGesturesEnabled != options.rotateGesturesEnabled) return false;
+ if (scrollGesturesEnabled != options.scrollGesturesEnabled) return false;
+ if (tiltGesturesEnabled != options.tiltGesturesEnabled) return false;
+ if (zoomGesturesEnabled != options.zoomGesturesEnabled) return false;
+ if (zoomControlsEnabled != options.zoomControlsEnabled) return false;
+ if (myLocationEnabled != options.myLocationEnabled) return false;
+ if (myLocationForegroundTintColor != options.myLocationForegroundTintColor) return false;
+ if (myLocationBackgroundTintColor != options.myLocationBackgroundTintColor) return false;
+ if (myLocationAccuracyTintColor != options.myLocationAccuracyTintColor) return false;
+ if (myLocationAccuracyAlpha != options.myLocationAccuracyAlpha) return false;
+ if (cameraPosition != null ? !cameraPosition.equals(options.cameraPosition) : options.cameraPosition != null)
+ return false;
+ if (!Arrays.equals(compassMargins, options.compassMargins)) return false;
+ if (!Arrays.equals(logoMargins, options.logoMargins)) return false;
+ if (!Arrays.equals(attributionMargins, options.attributionMargins)) return false;
+ if (myLocationForegroundDrawable != null ? !myLocationForegroundDrawable.equals(options.myLocationForegroundDrawable) : options.myLocationForegroundDrawable != null)
+ return false;
+ if (myLocationForegroundBearingDrawable != null ? !myLocationForegroundBearingDrawable.equals(options.myLocationForegroundBearingDrawable) : options.myLocationForegroundBearingDrawable != null)
+ return false;
+ if (myLocationBackgroundDrawable != null ? !myLocationBackgroundDrawable.equals(options.myLocationBackgroundDrawable) : options.myLocationBackgroundDrawable != null)
+ return false;
+ if (!Arrays.equals(myLocationBackgroundPadding, options.myLocationBackgroundPadding))
+ return false;
+ if (style != null ? !style.equals(options.style) : options.style != null) return false;
+ return accessToken != null ? accessToken.equals(options.accessToken) : options.accessToken == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = cameraPosition != null ? cameraPosition.hashCode() : 0;
+ result = 31 * result + (debugActive ? 1 : 0);
+ result = 31 * result + (compassEnabled ? 1 : 0);
+ result = 31 * result + compassGravity;
+ result = 31 * result + Arrays.hashCode(compassMargins);
+ result = 31 * result + (logoEnabled ? 1 : 0);
+ result = 31 * result + logoGravity;
+ result = 31 * result + Arrays.hashCode(logoMargins);
+ result = 31 * result + (attributionEnabled ? 1 : 0);
+ result = 31 * result + attributionGravity;
+ result = 31 * result + Arrays.hashCode(attributionMargins);
+ result = 31 * result + (minZoom != +0.0f ? Float.floatToIntBits(minZoom) : 0);
+ result = 31 * result + (maxZoom != +0.0f ? Float.floatToIntBits(maxZoom) : 0);
+ result = 31 * result + (rotateGesturesEnabled ? 1 : 0);
+ result = 31 * result + (scrollGesturesEnabled ? 1 : 0);
+ result = 31 * result + (tiltGesturesEnabled ? 1 : 0);
+ result = 31 * result + (zoomGesturesEnabled ? 1 : 0);
+ result = 31 * result + (zoomControlsEnabled ? 1 : 0);
+ result = 31 * result + (myLocationEnabled ? 1 : 0);
+ result = 31 * result + (myLocationForegroundDrawable != null ? myLocationForegroundDrawable.hashCode() : 0);
+ result = 31 * result + (myLocationForegroundBearingDrawable != null ? myLocationForegroundBearingDrawable.hashCode() : 0);
+ result = 31 * result + (myLocationBackgroundDrawable != null ? myLocationBackgroundDrawable.hashCode() : 0);
+ result = 31 * result + myLocationForegroundTintColor;
+ result = 31 * result + myLocationBackgroundTintColor;
+ result = 31 * result + Arrays.hashCode(myLocationBackgroundPadding);
+ result = 31 * result + myLocationAccuracyTintColor;
+ result = 31 * result + myLocationAccuracyAlpha;
+ result = 31 * result + (style != null ? style.hashCode() : 0);
+ result = 31 * result + (accessToken != null ? accessToken.hashCode() : 0);
+ return result;
+ }
}
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 c6ac6dc6e2..6c092ee0c8 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
@@ -119,24 +119,12 @@ final class NativeMapView {
nativeDestroySurface(mNativeMapViewPtr);
}
- public void pause() {
- nativePause(mNativeMapViewPtr);
- }
-
- public boolean isPaused() {
- return nativeIsPaused(mNativeMapViewPtr);
- }
-
- public void resume() {
- nativeResume(mNativeMapViewPtr);
- }
-
public void update() {
nativeUpdate(mNativeMapViewPtr);
}
- public void renderSync() {
- nativeRenderSync(mNativeMapViewPtr);
+ public void render() {
+ nativeRender(mNativeMapViewPtr);
}
public void resizeView(int width, int height) {
@@ -201,34 +189,12 @@ final class NativeMapView {
return nativeGetClasses(mNativeMapViewPtr);
}
- public void setDefaultTransitionDuration() {
- setDefaultTransitionDuration(0);
- }
-
- public long getDefaultTransitionDuration() {
- return nativeGetDefaultTransitionDuration(mNativeMapViewPtr);
- }
-
- public void setDefaultTransitionDuration(long milliseconds) {
- if (milliseconds < 0) {
- throw new IllegalArgumentException(
- "milliseconds cannot be negative.");
- }
-
- nativeSetDefaultTransitionDuration(mNativeMapViewPtr,
- milliseconds);
- }
-
public void setStyleUrl(String url) {
nativeSetStyleUrl(mNativeMapViewPtr, url);
}
public void setStyleJson(String newStyleJson) {
- setStyleJson(newStyleJson, "");
- }
-
- public void setStyleJson(String newStyleJson, String base) {
- nativeSetStyleJson(mNativeMapViewPtr, newStyleJson, base);
+ nativeSetStyleJson(mNativeMapViewPtr, newStyleJson);
}
public String getStyleJson() {
@@ -377,27 +343,30 @@ final class NativeMapView {
}
public long addMarker(Marker marker) {
- return nativeAddMarker(mNativeMapViewPtr, marker);
+ Marker[] markers = { marker };
+ return nativeAddMarkers(mNativeMapViewPtr, markers)[0];
}
public long[] addMarkers(List<Marker> markers) {
- return nativeAddMarkers(mNativeMapViewPtr, markers);
+ return nativeAddMarkers(mNativeMapViewPtr, markers.toArray(new Marker[markers.size()]));
}
public long addPolyline(Polyline polyline) {
- return nativeAddPolyline(mNativeMapViewPtr, polyline);
+ Polyline[] polylines = { polyline };
+ return nativeAddPolylines(mNativeMapViewPtr, polylines)[0];
}
public long[] addPolylines(List<Polyline> polylines) {
- return nativeAddPolylines(mNativeMapViewPtr, polylines);
+ return nativeAddPolylines(mNativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()]));
}
public long addPolygon(Polygon polygon) {
- return nativeAddPolygon(mNativeMapViewPtr, polygon);
+ Polygon[] polygons = { polygon };
+ return nativeAddPolygons(mNativeMapViewPtr, polygons)[0];
}
- public long[] addPolygons(List<Polygon> polygon) {
- return nativeAddPolygons(mNativeMapViewPtr, polygon);
+ public long[] addPolygons(List<Polygon> polygons) {
+ return nativeAddPolygons(mNativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()]));
}
public void updateMarker(Marker marker) {
@@ -405,7 +374,8 @@ final class NativeMapView {
}
public void removeAnnotation(long id) {
- nativeRemoveAnnotation(mNativeMapViewPtr, id);
+ long[] ids = { id };
+ removeAnnotations(ids);
}
public void removeAnnotations(long[] ids) {
@@ -476,8 +446,8 @@ final class NativeMapView {
nativeJumpTo(mNativeMapViewPtr, angle, center, pitch, zoom);
}
- public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom) {
- nativeEaseTo(mNativeMapViewPtr, angle, center, duration, pitch, zoom);
+ public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator) {
+ nativeEaseTo(mNativeMapViewPtr, angle, center, duration, pitch, zoom, easingInterpolator);
}
public void flyTo(double angle, LatLng center, long duration, double pitch, double zoom) {
@@ -533,15 +503,9 @@ final class NativeMapView {
private native void nativeDestroySurface(long nativeMapViewPtr);
- private native void nativePause(long nativeMapViewPtr);
-
- private native boolean nativeIsPaused(long nativeMapViewPtr);
-
- private native void nativeResume(long nativeMapViewPtr);
-
private native void nativeUpdate(long nativeMapViewPtr);
- private native void nativeRenderSync(long nativeMapViewPtr);
+ private native void nativeRender(long nativeMapViewPtr);
private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
@@ -558,15 +522,9 @@ final class NativeMapView {
private native List<String> nativeGetClasses(long nativeMapViewPtr);
- private native void nativeSetDefaultTransitionDuration(
- long nativeMapViewPtr, long duration);
-
- private native long nativeGetDefaultTransitionDuration(long nativeMapViewPtr);
-
private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
- private native void nativeSetStyleJson(long nativeMapViewPtr,
- String newStyleJson, String base);
+ private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson);
private native String nativeGetStyleJson(long nativeMapViewPtr);
@@ -630,21 +588,13 @@ final class NativeMapView {
private native void nativeResetNorth(long nativeMapViewPtr);
- private native long nativeAddMarker(long nativeMapViewPtr, Marker marker);
-
private native void nativeUpdateMarker(long nativeMapViewPtr, Marker marker);
- private native long[] nativeAddMarkers(long nativeMapViewPtr, List<Marker> markers);
-
- private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline);
-
- private native long[] nativeAddPolylines(long mNativeMapViewPtr, List<Polyline> polygon);
-
- private native long nativeAddPolygon(long mNativeMapViewPtr, Polygon polygon);
+ private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers);
- private native long[] nativeAddPolygons(long mNativeMapViewPtr, List<Polygon> polygon);
+ private native long[] nativeAddPolylines(long mNativeMapViewPtr, Polyline[] polylines);
- private native void nativeRemoveAnnotation(long nativeMapViewPtr, long id);
+ private native long[] nativeAddPolygons(long mNativeMapViewPtr, Polygon[] polygons);
private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
@@ -682,7 +632,7 @@ final class NativeMapView {
private native void nativeJumpTo(long nativeMapViewPtr, double angle, LatLng center, double pitch, double zoom);
- private native void nativeEaseTo(long nativeMapViewPtr, double angle, LatLng center, long duration, double pitch, double zoom);
+ private native void nativeEaseTo(long nativeMapViewPtr, double angle, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator);
private native void nativeFlyTo(long nativeMapViewPtr, double angle, LatLng center, long duration, double pitch, double zoom);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index 9482b1a2f7..d37c3a02ea 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -57,13 +57,15 @@ public class Projection {
public VisibleRegion getVisibleRegion() {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
- int viewportWidth = mMapView.getWidth();
- int viewportHeight = mMapView.getHeight();
+ float left = mMapView.getContentPaddingLeft();
+ float right = mMapView.getWidth() - mMapView.getContentPaddingRight();
+ float top = mMapView.getContentPaddingTop();
+ float bottom = mMapView.getHeight() - mMapView.getContentPaddingBottom();
- LatLng topLeft = fromScreenLocation(new PointF(0, 0));
- LatLng topRight = fromScreenLocation(new PointF(viewportWidth, 0));
- LatLng bottomRight = fromScreenLocation(new PointF(viewportWidth, viewportHeight));
- LatLng bottomLeft = fromScreenLocation(new PointF(0, viewportHeight));
+ LatLng topLeft = fromScreenLocation(new PointF(left, top));
+ LatLng topRight = fromScreenLocation(new PointF(right, top));
+ LatLng bottomRight = fromScreenLocation(new PointF(right, bottom));
+ LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom));
builder.include(topLeft)
.include(topRight)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
index ffdb57de8c..3d96727758 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
@@ -1,14 +1,19 @@
package com.mapbox.mapboxsdk.maps;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
+import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
/**
* Support Fragment wrapper around a map view.
@@ -32,6 +37,15 @@ public class SupportMapFragment extends Fragment {
/**
* Creates a MapFragment instance
*
+ * @return MapFragment created
+ */
+ public static SupportMapFragment newInstance() {
+ return new SupportMapFragment();
+ }
+
+ /**
+ * Creates a MapFragment instance
+ *
* @param mapboxMapOptions The configuration options to be used.
* @return MapFragment created.
*/
@@ -44,7 +58,7 @@ public class SupportMapFragment extends Fragment {
}
/**
- * Creates the fragment view hierachy.
+ * Creates the fragment view hierarchy.
*
* @param inflater Inflater used to inflate content.
* @param container The parent layout for the map fragment.
@@ -54,11 +68,66 @@ public class SupportMapFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- MapboxMapOptions options = getArguments().getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS);
+ MapboxMapOptions options = null;
+
+ // Get bundle
+ Bundle bundle = getArguments();
+ if (bundle != null && bundle.containsKey(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS)) {
+ options = bundle.getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS);
+ }
+
+ // Assign an AccessToken if needed
+ if (options == null || options.getAccessToken() == null) {
+ String token = null;
+ if (MapboxAccountManager.getInstance() != null) {
+ token = MapboxAccountManager.getInstance().getAccessToken();
+ } else {
+ token = getToken(inflater.getContext());
+ }
+ if (TextUtils.isEmpty(token)) {
+ throw new InvalidAccessTokenException();
+ }
+ if (options == null) {
+ options = new MapboxMapOptions().accessToken(token);
+ } else {
+ options.accessToken(token);
+ }
+ }
return mMap = new MapView(inflater.getContext(), options);
}
/**
+ * <p>
+ * Returns the Mapbox access token set in the app resources.
+ * </p>
+ * It will first search the application manifest for a {@link MapboxConstants#KEY_META_DATA_MANIFEST}
+ * meta-data value. If not found it will then attempt to load the access token from the
+ * {@code res/raw/token.txt} development file.
+ *
+ * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}.
+ * @return The Mapbox access token or null if not found.
+ * @see MapboxConstants#KEY_META_DATA_MANIFEST
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
+ */
+ @Deprecated
+ private String getToken(@NonNull Context context) {
+ try {
+ // read out AndroidManifest
+ PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ String token = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_MANIFEST);
+ if (token == null || token.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+ return token;
+ } catch (Exception e) {
+ // use fallback on string resource, used for development
+ int tokenResId = context.getResources().getIdentifier("mapbox_access_token", "string", context.getPackageName());
+ return tokenResId != 0 ? context.getString(tokenResId) : null;
+ }
+ }
+
+ /**
* Called when the fragment view hierarchy is created.
*
* @param view The content view of the fragment
@@ -142,4 +211,4 @@ public class SupportMapFragment extends Fragment {
public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
mOnMapReadyCallback = onMapReadyCallback;
}
-} \ No newline at end of file
+}
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 90147929e9..30492bc421 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
@@ -5,7 +5,7 @@ import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.maps.widgets.UserLocationView;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
/**
* Settings for the user location and bearing tracking of a MapboxMap.
@@ -14,13 +14,14 @@ public class TrackingSettings {
private MapView mapView;
private UiSettings uiSettings;
- private boolean dismissTrackingOnGesture = true;
+ private boolean dismissLocationTrackingOnGesture = true;
+ private boolean dismissBearingTrackingOnGesture = true;
@MyLocationTracking.Mode
- private int mMyLocationTrackingMode;
+ private int myLocationTrackingMode;
@MyBearingTracking.Mode
- private int mMyBearingTrackingMode;
+ private int myBearingTrackingMode;
TrackingSettings(@NonNull MapView mapView, UiSettings uiSettings) {
this.mapView = mapView;
@@ -42,9 +43,9 @@ public class TrackingSettings {
*/
@UiThread
public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
- mMyLocationTrackingMode = myLocationTrackingMode;
+ this.myLocationTrackingMode = myLocationTrackingMode;
mapView.setMyLocationTrackingMode(myLocationTrackingMode);
- validateGesturesForTrackingModes();
+ validateGesturesForLocationTrackingMode();
}
/**
@@ -57,7 +58,7 @@ public class TrackingSettings {
@UiThread
@MyLocationTracking.Mode
public int getMyLocationTrackingMode() {
- return mMyLocationTrackingMode;
+ return myLocationTrackingMode;
}
/**
@@ -66,7 +67,7 @@ public class TrackingSettings {
* </p>
* Shows the direction the user is heading.
* <p>
- * When location tracking is disabled the direction of {@link UserLocationView} is rotated
+ * When location tracking is disabled the direction of {@link MyLocationView} is rotated
* When location tracking is enabled the {@link MapView} is rotated based on bearing value.
* </p>
* See {@link MyBearingTracking} for different values.
@@ -77,8 +78,9 @@ public class TrackingSettings {
*/
@UiThread
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
- mMyBearingTrackingMode = myBearingTrackingMode;
+ this.myBearingTrackingMode = myBearingTrackingMode;
mapView.setMyBearingTrackingMode(myBearingTrackingMode);
+ validateGesturesForBearingTrackingMode();
}
/**
@@ -89,52 +91,137 @@ public class TrackingSettings {
* @see MyBearingTracking
*/
@UiThread
- @MyLocationTracking.Mode
+ @MyBearingTracking.Mode
public int getMyBearingTrackingMode() {
- return mMyBearingTrackingMode;
+ return myBearingTrackingMode;
}
/**
* Returns if the tracking modes will be dismissed when a gesture occurs.
*
* @return True to indicate the tracking modes will be dismissed.
- */
+ * @deprecated use @link #isAllDismissTrackingOnGestureinstead
+ */
+ @Deprecated
public boolean isDismissTrackingOnGesture() {
- return dismissTrackingOnGesture;
+ return dismissLocationTrackingOnGesture && dismissBearingTrackingOnGesture;
+ }
+
+ /**
+ * Returns if all tracking modes will be dismissed when a gesture occurs.
+ *
+ * @return True to indicate that location and bearing tracking will be dismissed.
+ */
+ public boolean isAllDismissTrackingOnGesture() {
+ return dismissLocationTrackingOnGesture && dismissBearingTrackingOnGesture;
}
/**
* Set the dismissal of the tracking modes if a gesture occurs.
*
* @param dismissTrackingOnGesture True to dismiss the tracking modes.
+ * @deprecated use @link #setDismissAllTrackingOnGesture instead
*/
+ @Deprecated
public void setDismissTrackingOnGesture(boolean dismissTrackingOnGesture) {
- this.dismissTrackingOnGesture = dismissTrackingOnGesture;
- validateGesturesForTrackingModes();
+ setDismissAllTrackingOnGesture(dismissTrackingOnGesture);
+ }
+
+ /**
+ * Set the dismissal of the tracking modes if a gesture occurs.
+ *
+ * @param dismissTrackingOnGesture True to dismiss all the tracking modes.
+ */
+ public void setDismissAllTrackingOnGesture(boolean dismissTrackingOnGesture) {
+ dismissLocationTrackingOnGesture = dismissTrackingOnGesture;
+ dismissBearingTrackingOnGesture = dismissTrackingOnGesture;
+ validateAllGesturesForTrackingModes();
+ }
+
+ /**
+ * Set the dismissal of the tracking modes if a gesture occurs.
+ *
+ * @param dismissLocationTrackingOnGesture True to dismiss the location tracking mode.
+ */
+ public void setDismissLocationTrackingOnGesture(boolean dismissLocationTrackingOnGesture) {
+ this.dismissLocationTrackingOnGesture = dismissLocationTrackingOnGesture;
+ validateGesturesForLocationTrackingMode();
+ }
+
+ /**
+ * Returns if the location tracking will be disabled when a gesture occurs
+ *
+ * @return True if location tracking will be disabled.
+ */
+ public boolean isDismissLocationTrackingOnGesture() {
+ return dismissLocationTrackingOnGesture;
+ }
+
+ /**
+ * Set the dismissal of the bearing tracking modes if a gesture occurs.
+ *
+ * @param dismissBearingTrackingOnGesture True to dimsiss the bearinf tracking mode
+ */
+ public void setDismissBearingTrackingOnGesture(boolean dismissBearingTrackingOnGesture) {
+ this.dismissBearingTrackingOnGesture = dismissBearingTrackingOnGesture;
+ validateGesturesForBearingTrackingMode();
}
- private void validateGesturesForTrackingModes() {
- if (!dismissTrackingOnGesture) {
- int myLocationTrackingMode = getMyLocationTrackingMode();
- int myBearingTrackingMode = getMyBearingTrackingMode();
+ /**
+ * Returns if bearing will disabled when a gesture occurs
+ *
+ * @return True if bearing tracking will be disabled
+ */
+ public boolean isDismissBearingTrackingOnGesture() {
+ return dismissBearingTrackingOnGesture;
+ }
- // Enable/disable gestures based on tracking mode
+ /**
+ * Returns if location tracking is disabled
+ *
+ * @return True if location tracking is disabled.
+ */
+ public boolean isLocationTrackingDisabled() {
+ return myLocationTrackingMode == MyLocationTracking.TRACKING_NONE;
+ }
+
+ /**
+ * Retyrns uf bearing tracking is disabled
+ *
+ * @return True if bearing tracking will be disabled.
+ */
+ public boolean isBearingTrackingDisabled() {
+ return myBearingTrackingMode == MyBearingTracking.NONE;
+ }
+
+ private void validateAllGesturesForTrackingModes() {
+ validateGesturesForBearingTrackingMode();
+ validateGesturesForLocationTrackingMode();
+ }
+
+ private void validateGesturesForLocationTrackingMode() {
+ int myLocationTrackingMode = getMyLocationTrackingMode();
+ if (!dismissLocationTrackingOnGesture) {
if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
uiSettings.setScrollGesturesEnabled(true);
- uiSettings.setRotateGesturesEnabled(true);
} else {
uiSettings.setScrollGesturesEnabled(false);
- uiSettings.setRotateGesturesEnabled((myBearingTrackingMode == MyBearingTracking.NONE));
}
+ } else {
+ uiSettings.setScrollGesturesEnabled(true);
}
}
- /**
- * Return if location tracking is disabled
- *
- * @return True if location tracking is disabled.
- */
- public boolean isLocationTrackingDisabled() {
- return mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE;
+ private void validateGesturesForBearingTrackingMode() {
+ int myBearingTrackingMode = getMyBearingTrackingMode();
+ if (!dismissBearingTrackingOnGesture) {
+ if (myBearingTrackingMode == MyBearingTracking.NONE) {
+ uiSettings.setRotateGesturesEnabled(true);
+ } else {
+ uiSettings.setRotateGesturesEnabled(false);
+ }
+ } else {
+ uiSettings.setRotateGesturesEnabled(true);
+ }
}
}
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 f87ddb4ca1..3cd9efb13e 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
@@ -1,13 +1,12 @@
package com.mapbox.mapboxsdk.maps;
-import android.support.annotation.FloatRange;
+import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
-import android.util.Log;
import android.view.Gravity;
import android.view.View;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
/**
* Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings().
@@ -20,11 +19,19 @@ public class UiSettings {
private ViewSettings logoSettings;
private ViewSettings attributionSettings;
- private boolean rotateGesturesEnabled;
- private boolean tiltGesturesEnabled;
- private boolean zoomGesturesEnabled;
+ private boolean rotateGesturesEnabled = true;
+ private boolean rotateGestureChangeAllowed = true;
+
+ private boolean tiltGesturesEnabled = true;
+ private boolean tiltGestureChangeAllowed = true;
+
+ private boolean zoomGesturesEnabled = true;
+ private boolean zoomGestureChangeAllowed = true;
+
+ private boolean scrollGesturesEnabled = true;
+ private boolean scrollGestureChangeAllowed = true;
+
private boolean zoomControlsEnabled;
- private boolean scrollGesturesEnabled;
UiSettings(@NonNull MapView mapView) {
this.mapView = mapView;
@@ -232,11 +239,11 @@ public class UiSettings {
/**
* <p>
- * Enables or disables the Mapbox logo.
+ * Enables or disables the attribution.
* </p>
- * By default, the compass is enabled.
+ * By default, the attribution is enabled.
*
- * @param enabled True to enable the logo; false to disable the logo.
+ * @param enabled True to enable the attribution; false to disable the attribution.
*/
public void setAttributionEnabled(boolean enabled) {
attributionSettings.setEnabled(enabled);
@@ -244,9 +251,9 @@ public class UiSettings {
}
/**
- * Returns whether the logo is enabled.
+ * Returns whether the attribution is enabled.
*
- * @return True if the logo is enabled; false if the logo is disabled.
+ * @return True if the attribution is enabled; false if the attribution is disabled.
*/
public boolean isAttributionEnabled() {
return attributionSettings.isEnabled();
@@ -254,10 +261,9 @@ public class UiSettings {
/**
* <p>
- * Sets the gravity of the logo view. Use this to change the corner of the map view that the
- * Mapbox logo is displayed in.
+ * Sets the gravity of the attribution.
* </p>
- * By default, the logo is in the bottom left corner.
+ * By default, the attribution is in the bottom left corner next to the Mapbox logo.
*
* @param gravity One of the values from {@link Gravity}.
* @see Gravity
@@ -277,8 +283,7 @@ public class UiSettings {
}
/**
- * Sets the margins of the logo view. Use this to change the distance of the Mapbox logo from the
- * map view edge.
+ * Sets the margins of the attribution view.
*
* @param left The left margin in pixels.
* @param top The top margin in pixels.
@@ -291,7 +296,29 @@ public class UiSettings {
}
/**
- * Returns the left side margin of the logo
+ * <p>
+ * Sets the tint of the attribution view. Use this to change the color of the attribution.
+ * </p>
+ * By default, the logo is tinted with the primary color of your theme.
+ *
+ * @param tintColor Color to tint the attribution.
+ */
+ public void setAttributionTintColor(@ColorInt int tintColor) {
+ attributionSettings.setTintColor(tintColor);
+ mapView.setAtttibutionTintColor(tintColor);
+ }
+
+ /**
+ * Returns the tint color value of the attribution view.
+ *
+ * @return The tint color
+ */
+ public int getAttributionTintColor() {
+ return attributionSettings.getTintColor();
+ }
+
+ /**
+ * Returns the left side margin of the attribution view.
*
* @return The left margin in pixels
*/
@@ -300,7 +327,7 @@ public class UiSettings {
}
/**
- * Returns the top side margin of the logo
+ * Returns the top side margin of the attribution view.
*
* @return The top margin in pixels
*/
@@ -309,7 +336,7 @@ public class UiSettings {
}
/**
- * Returns the right side margin of the logo
+ * Returns the right side margin of the attribution view.
*
* @return The right margin in pixels
*/
@@ -339,7 +366,9 @@ public class UiSettings {
* @param rotateGesturesEnabled If true, rotating is enabled.
*/
public void setRotateGesturesEnabled(boolean rotateGesturesEnabled) {
- this.rotateGesturesEnabled = rotateGesturesEnabled;
+ if (rotateGestureChangeAllowed) {
+ this.rotateGesturesEnabled = rotateGesturesEnabled;
+ }
}
/**
@@ -351,6 +380,14 @@ public class UiSettings {
return rotateGesturesEnabled;
}
+ void setRotateGestureChangeAllowed(boolean rotateGestureChangeAllowed) {
+ this.rotateGestureChangeAllowed = rotateGestureChangeAllowed;
+ }
+
+ boolean isRotateGestureChangeAllowed() {
+ return rotateGestureChangeAllowed;
+ }
+
/**
* <p>
* Changes whether the user may tilt the map.
@@ -364,7 +401,9 @@ public class UiSettings {
* @param tiltGesturesEnabled If true, tilting is enabled.
*/
public void setTiltGesturesEnabled(boolean tiltGesturesEnabled) {
- this.tiltGesturesEnabled = tiltGesturesEnabled;
+ if (tiltGestureChangeAllowed) {
+ this.tiltGesturesEnabled = tiltGesturesEnabled;
+ }
}
/**
@@ -376,6 +415,14 @@ public class UiSettings {
return tiltGesturesEnabled;
}
+ void setTiltGestureChangeAllowed(boolean tiltGestureChangeAllowed) {
+ this.tiltGestureChangeAllowed = tiltGestureChangeAllowed;
+ }
+
+ boolean isTiltGestureChangeAllowed() {
+ return tiltGestureChangeAllowed;
+ }
+
/**
* <p>
* Changes whether the user may zoom the map.
@@ -389,7 +436,9 @@ public class UiSettings {
* @param zoomGesturesEnabled If true, zooming is enabled.
*/
public void setZoomGesturesEnabled(boolean zoomGesturesEnabled) {
- this.zoomGesturesEnabled = zoomGesturesEnabled;
+ if (zoomGestureChangeAllowed) {
+ this.zoomGesturesEnabled = zoomGesturesEnabled;
+ }
}
/**
@@ -401,6 +450,14 @@ public class UiSettings {
return zoomGesturesEnabled;
}
+ void setZoomGestureChangeAllowed(boolean zoomGestureChangeAllowed) {
+ this.zoomGestureChangeAllowed = zoomGestureChangeAllowed;
+ }
+
+ boolean isZoomGestureChangeAllowed() {
+ return zoomGestureChangeAllowed;
+ }
+
/**
* <p>
* Sets whether the zoom controls are enabled.
@@ -439,7 +496,9 @@ public class UiSettings {
* @param scrollGesturesEnabled If true, scrolling is enabled.
*/
public void setScrollGesturesEnabled(boolean scrollGesturesEnabled) {
- this.scrollGesturesEnabled = scrollGesturesEnabled;
+ if (scrollGestureChangeAllowed) {
+ this.scrollGesturesEnabled = scrollGesturesEnabled;
+ }
}
/**
@@ -451,6 +510,14 @@ public class UiSettings {
return scrollGesturesEnabled;
}
+ void setScrollGestureChangeAllowed(boolean scrollGestureChangeAllowed) {
+ this.scrollGestureChangeAllowed = scrollGestureChangeAllowed;
+ }
+
+ boolean isScrollGestureChangeAllowed() {
+ return scrollGestureChangeAllowed;
+ }
+
/**
* <p>
* Sets the preference for whether all gestures should be enabled or disabled.
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java
index 0726b7bbbf..f08a1bdeb4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java
@@ -8,6 +8,7 @@ class ViewSettings {
private boolean enabled;
private int gravity;
private int[]margins;
+ private int tintColor;
public ViewSettings() {
margins = new int[4];
@@ -36,4 +37,12 @@ class ViewSettings {
public void setMargins(int[] margins) {
this.margins = margins;
}
+
+ public int getTintColor() {
+ return tintColor;
+ }
+
+ public void setTintColor(int tintColor) {
+ this.tintColor = tintColor;
+ }
}
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
new file mode 100644
index 0000000000..aed4e87c07
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -0,0 +1,705 @@
+package com.mapbox.mapboxsdk.maps.widgets;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.location.Location;
+import android.os.SystemClock;
+import android.support.annotation.ColorInt;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.constants.MyBearingTracking;
+import com.mapbox.mapboxsdk.constants.MyLocationTracking;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.location.LocationListener;
+import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Projection;
+import com.mapbox.mapboxsdk.maps.UiSettings;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * UI element overlaid on a map to show the user's location.
+ */
+public class MyLocationView extends View {
+
+ private MyLocationBehavior myLocationBehavior;
+ private MapboxMap mapboxMap;
+ private Projection projection;
+ private int maxSize;
+ private int[] contentPadding = new int[4];
+
+ private Location location;
+ private LatLng latLng;
+ private LatLng interpolatedLocation;
+ private LatLng previousLocation;
+ private long locationUpdateTimestamp;
+
+ private float gpsDirection;
+ private float previousDirection;
+
+ private float accuracy = 0;
+ private Paint accuracyPaint = new Paint();
+
+ private ValueAnimator locationChangeAnimator;
+ private ValueAnimator accuracyAnimator;
+ private ObjectAnimator directionAnimator;
+
+ private Drawable foregroundDrawable;
+ private Drawable foregroundBearingDrawable;
+ private Drawable backgroundDrawable;
+
+ private int foregroundTintColor;
+ private int backgroundTintColor;
+
+ private Rect foregroundBounds;
+ private Rect backgroundBounds;
+
+ private int backgroundOffsetLeft;
+ private int backgroundOffsetTop;
+ private int backgroundOffsetRight;
+ private int backgroundOffsetBottom;
+
+ @MyLocationTracking.Mode
+ private int myLocationTrackingMode;
+
+ @MyBearingTracking.Mode
+ private int myBearingTrackingMode;
+
+ private GpsLocationListener userLocationListener;
+ private CompassListener compassListener;
+
+ public MyLocationView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public MyLocationView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public MyLocationView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ private void init(Context context) {
+ setEnabled(false);
+ myLocationBehavior = new MyLocationBehaviorFactory().getBehavioralModel(MyLocationTracking.TRACKING_NONE);
+ compassListener = new CompassListener(context);
+ maxSize = (int) context.getResources().getDimension(R.dimen.my_locationview_size);
+ }
+
+ public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) {
+ if (defaultDrawable == null || bearingDrawable == null) {
+ return;
+ }
+ if (defaultDrawable.getIntrinsicWidth() != bearingDrawable.getIntrinsicWidth() || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) {
+ throw new RuntimeException("The dimensions from location and bearing drawables should be match");
+ }
+
+ foregroundDrawable = defaultDrawable;
+ foregroundBearingDrawable = bearingDrawable;
+ setForegroundDrawableTint(foregroundTintColor);
+
+ invalidateBounds();
+ }
+
+ public final void setForegroundDrawableTint(@ColorInt int color) {
+ if (color != Color.TRANSPARENT) {
+ foregroundTintColor = color;
+ if (foregroundDrawable != null) {
+ foregroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ if (foregroundBearingDrawable != null) {
+ foregroundBearingDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ }
+ invalidate();
+ }
+
+ public final void setShadowDrawable(Drawable drawable) {
+ setShadowDrawable(drawable, 0, 0, 0, 0);
+ }
+
+ public final void setShadowDrawable(Drawable drawable, int left, int top, int right, int bottom) {
+ if (drawable != null) {
+ backgroundDrawable = drawable;
+ }
+
+ backgroundOffsetLeft = left;
+ backgroundOffsetTop = top;
+ backgroundOffsetRight = right;
+ backgroundOffsetBottom = bottom;
+
+ setShadowDrawableTint(backgroundTintColor);
+
+ invalidateBounds();
+ }
+
+ public final void setShadowDrawableTint(@ColorInt int color) {
+ if (color != Color.TRANSPARENT) {
+ backgroundTintColor = color;
+ if (backgroundDrawable == null) {
+ return;
+ }
+ backgroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ invalidate();
+ }
+
+ public final void setAccuracyTint(@ColorInt int color) {
+ int alpha = accuracyPaint.getAlpha();
+ accuracyPaint.setColor(color);
+ accuracyPaint.setAlpha(alpha);
+ invalidate();
+ }
+
+ public final void setAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) {
+ accuracyPaint.setAlpha(alpha);
+ invalidate();
+ }
+
+ private void invalidateBounds() {
+ if (backgroundDrawable == null || foregroundDrawable == null || foregroundBearingDrawable == null) {
+ return;
+ }
+
+ int backgroundWidth = backgroundDrawable.getIntrinsicWidth();
+ int backgroundHeight = backgroundDrawable.getIntrinsicHeight();
+
+ int foregroundWidth = foregroundDrawable.getIntrinsicWidth();
+ int foregroundHeight = foregroundDrawable.getIntrinsicHeight();
+
+ int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight;
+ int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom;
+
+ int accuracyWidth = 2 * maxSize;
+
+ backgroundBounds = new Rect(accuracyWidth - (backgroundWidth / 2) + horizontalOffset, accuracyWidth + verticalOffset - (backgroundWidth / 2), accuracyWidth + (backgroundWidth / 2) + horizontalOffset, accuracyWidth + (backgroundHeight / 2) + verticalOffset);
+ foregroundBounds = new Rect(accuracyWidth - (foregroundWidth / 2), accuracyWidth - (foregroundHeight / 2), accuracyWidth + (foregroundWidth / 2), accuracyWidth + (foregroundHeight / 2));
+
+ // invoke a new measure
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null) {
+ // Not ready yet
+ return;
+ }
+
+ // Draw circle
+ float metersPerPixel = (float) projection.getMetersPerPixelAtLatitude(location.getLatitude());
+ float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel;
+ float maxRadius = getWidth() / 2;
+ canvas.drawCircle(foregroundBounds.centerX(), foregroundBounds.centerY(), accuracyPixels <= maxRadius ? accuracyPixels : maxRadius, accuracyPaint);
+
+ // Draw shadow
+ if (backgroundDrawable != null) {
+ backgroundDrawable.draw(canvas);
+ }
+
+ // Draw foreground
+ if (myBearingTrackingMode == MyBearingTracking.NONE) {
+ if (foregroundDrawable != null) {
+ foregroundDrawable.draw(canvas);
+ }
+ } else if (foregroundBearingDrawable != null && foregroundBounds != null) {
+ foregroundBearingDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (foregroundDrawable != null && foregroundBounds != null) {
+ foregroundDrawable.setBounds(foregroundBounds);
+ }
+
+ if (foregroundBearingDrawable != null && foregroundBounds != null) {
+ foregroundBearingDrawable.setBounds(foregroundBounds);
+ }
+
+ if (backgroundDrawable != null && backgroundBounds != null) {
+ backgroundDrawable.setBounds(backgroundBounds);
+ }
+
+ setMeasuredDimension(4 * maxSize, 4 * maxSize);
+ }
+
+ public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
+ setRotationX((float) tilt);
+ }
+
+ void updateOnNextFrame() {
+ mapboxMap.invalidate();
+ }
+
+ public void onPause() {
+ compassListener.onPause();
+ toggleGps(false);
+ }
+
+ public void onResume() {
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ compassListener.onResume();
+ }
+ if (isEnabled()) {
+ toggleGps(true);
+ }
+ }
+
+ public void update() {
+ if (isEnabled()) {
+ myLocationBehavior.invalidate();
+ } else {
+ setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public void setMapboxMap(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ this.projection = mapboxMap.getProjection();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
+ toggleGps(enabled);
+ }
+
+ /**
+ * Enabled / Disable GPS location updates along with updating the UI
+ *
+ * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
+ */
+ private void toggleGps(boolean enableGps) {
+ LocationServices locationServices = LocationServices.getLocationServices(getContext());
+ if (enableGps) {
+ // Set an initial location if one available
+ Location lastLocation = locationServices.getLastLocation();
+
+ if (lastLocation != null) {
+ setLocation(lastLocation);
+ }
+
+ if (userLocationListener == null) {
+ userLocationListener = new GpsLocationListener(this);
+ }
+
+ locationServices.addLocationListener(userLocationListener);
+ } else {
+ // Disable location and user dot
+ location = null;
+ locationServices.removeLocationListener(userLocationListener);
+ }
+
+ locationServices.toggleGPS(enableGps);
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public void setLocation(Location location) {
+ if (location == null) {
+ this.location = null;
+ return;
+ }
+
+ this.location = location;
+ myLocationBehavior.updateLatLng(location);
+ }
+
+ public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
+ this.myBearingTrackingMode = myBearingTrackingMode;
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ compassListener.onResume();
+ } else {
+ compassListener.onPause();
+ if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
+ // always face north
+ gpsDirection = 0;
+ setCompass(gpsDirection);
+ }
+ }
+ invalidate();
+ update();
+ }
+
+ public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
+ this.myLocationTrackingMode = myLocationTrackingMode;
+
+ MyLocationBehaviorFactory factory = new MyLocationBehaviorFactory();
+ myLocationBehavior = factory.getBehavioralModel(myLocationTrackingMode);
+
+ if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && location != null) {
+ // center map directly if we have a location fix
+ myLocationBehavior.updateLatLng(location);
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(location)));
+ }
+ invalidate();
+ update();
+ }
+
+ private void setCompass(float bearing) {
+ float oldDir = previousDirection;
+ if (directionAnimator != null) {
+ oldDir = (Float) directionAnimator.getAnimatedValue();
+ directionAnimator.end();
+ directionAnimator = null;
+ }
+
+ float newDir = bearing;
+ float diff = oldDir - newDir;
+ if (diff > 180.0f) {
+ newDir += 360.0f;
+ } else if (diff < -180.0f) {
+ newDir -= 360.f;
+ }
+ previousDirection = newDir;
+
+ directionAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, oldDir, newDir);
+ directionAnimator.setDuration(1000);
+ directionAnimator.start();
+ }
+
+ public float getCenterX() {
+ return getX() + getMeasuredWidth() / 2;
+ }
+
+ public float getCenterY() {
+ return getY() + getMeasuredHeight() / 2;
+ }
+
+ public void setContentPadding(int[] padding) {
+ contentPadding = padding;
+ }
+
+ private static class GpsLocationListener implements LocationListener {
+
+ private WeakReference<MyLocationView> mUserLocationView;
+
+ public GpsLocationListener(MyLocationView myLocationView) {
+ mUserLocationView = new WeakReference<>(myLocationView);
+ }
+
+ /**
+ * Callback method for receiving location updates from LocationServices.
+ *
+ * @param location The new Location data
+ */
+ @Override
+ public void onLocationChanged(Location location) {
+ MyLocationView locationView = mUserLocationView.get();
+ if (locationView != null) {
+ locationView.setLocation(location);
+ }
+ }
+ }
+
+ private class CompassListener implements SensorEventListener {
+
+ private SensorManager mSensorManager;
+ private Sensor mAccelerometer;
+ private Sensor mMagnetometer;
+ private boolean paused;
+
+ private float mCurrentDegree = 0f;
+
+ private float[] mOrientation = new float[3];
+ private float[] mGData = new float[3];
+ private float[] mMData = new float[3];
+ private float[] mR = new float[16];
+ private float[] mI = new float[16];
+
+ // Controls the sensor updateLatLng rate in milliseconds
+ private static final int UPDATE_RATE_MS = 500;
+
+ // Compass data
+ private long mCompassUpdateNextTimestamp = 0;
+
+ public CompassListener(Context context) {
+ mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
+ }
+
+ public void onResume() {
+ paused = false;
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
+ }
+
+ public void onPause() {
+ paused = true;
+ mSensorManager.unregisterListener(this, mAccelerometer);
+ mSensorManager.unregisterListener(this, mMagnetometer);
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (paused) {
+ return;
+ }
+
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime < mCompassUpdateNextTimestamp) {
+ return;
+ }
+
+ int type = event.sensor.getType();
+ float[] data;
+ if (type == Sensor.TYPE_ACCELEROMETER) {
+ data = mGData;
+ } else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
+ data = mMData;
+ } else {
+ // we should not be here.
+ return;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ data[i] = event.values[i];
+ }
+
+ SensorManager.getRotationMatrix(mR, mI, mGData, mMData);
+ SensorManager.getOrientation(mR, mOrientation);
+ setCompass((int) (mOrientation[0] * 180.0f / Math.PI));
+ mCompassUpdateNextTimestamp = currentTime + UPDATE_RATE_MS;
+ }
+
+ public float getCurrentDegree() {
+ return mCurrentDegree;
+ }
+
+ public boolean isPaused() {
+ return paused;
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+ }
+
+ private class MarkerCoordinateAnimatorListener implements ValueAnimator.AnimatorUpdateListener {
+
+ private MyLocationBehavior behavior;
+ private double fromLat;
+ private double fromLng;
+ private double toLat;
+ private double toLng;
+
+ private MarkerCoordinateAnimatorListener(MyLocationBehavior myLocationBehavior, LatLng from, LatLng to) {
+ behavior = myLocationBehavior;
+ fromLat = from.getLatitude();
+ fromLng = from.getLongitude();
+ toLat = to.getLatitude();
+ toLng = to.getLongitude();
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float frac = animation.getAnimatedFraction();
+ double latitude = fromLat + (toLat - fromLat) * frac;
+ double longitude = fromLng + (toLng - fromLng) * frac;
+ behavior.updateLatLng(latitude, longitude);
+ updateOnNextFrame();
+ }
+ }
+
+ private class MyLocationBehaviorFactory {
+
+ public MyLocationBehavior getBehavioralModel(@MyLocationTracking.Mode int mode) {
+ if (mode == MyLocationTracking.TRACKING_NONE) {
+ return new MyLocationShowBehavior();
+ } else {
+ return new MyLocationTrackingBehavior();
+ }
+ }
+ }
+
+ private abstract class MyLocationBehavior {
+
+ abstract void updateLatLng(@NonNull Location location);
+
+ public void updateLatLng(double lat, double lon) {
+ if (latLng != null) {
+ latLng.setLatitude(lat);
+ latLng.setLongitude(lon);
+ }
+ }
+
+ protected void updateAccuracy(@NonNull Location location) {
+ if (accuracyAnimator != null && accuracyAnimator.isRunning()) {
+ // use current accuracy as a starting point
+ accuracy = (Float) accuracyAnimator.getAnimatedValue();
+ accuracyAnimator.end();
+ }
+
+ accuracyAnimator = ValueAnimator.ofFloat(accuracy * 10, location.getAccuracy() * 10);
+ accuracyAnimator.setDuration(750);
+ accuracyAnimator.start();
+ accuracy = location.getAccuracy();
+ }
+
+ abstract void invalidate();
+ }
+
+ private class MyLocationTrackingBehavior extends MyLocationBehavior {
+
+ @Override
+ void updateLatLng(@NonNull Location location) {
+ if (latLng == null) {
+ // first location fix
+ latLng = new LatLng(location);
+ locationUpdateTimestamp = SystemClock.elapsedRealtime();
+ }
+
+ // updateLatLng timestamp
+ long previousUpdateTimeStamp = locationUpdateTimestamp;
+ locationUpdateTimestamp = SystemClock.elapsedRealtime();
+
+ // calculate animation duration
+ long locationUpdateDuration;
+ if (previousUpdateTimeStamp == 0) {
+ locationUpdateDuration = 0;
+ } else {
+ locationUpdateDuration = locationUpdateTimestamp - previousUpdateTimeStamp;
+ }
+
+ // calculate interpolated location
+ previousLocation = latLng;
+ latLng = new LatLng(location);
+ interpolatedLocation = new LatLng((latLng.getLatitude() + previousLocation.getLatitude()) / 2, (latLng.getLongitude() + previousLocation.getLongitude()) / 2);
+
+ // build new camera
+ CameraPosition.Builder builder = new CameraPosition.Builder().target(interpolatedLocation);
+
+ // add direction
+ if (myBearingTrackingMode == MyBearingTracking.GPS) {
+ if (location.hasBearing()) {
+ builder.bearing(location.getBearing());
+ }
+ gpsDirection = 0;
+ setCompass(gpsDirection);
+ } else if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ if (!compassListener.isPaused()) {
+ builder.bearing(compassListener.getCurrentDegree());
+ setCompass(0);
+ }
+ }
+
+ // accuracy
+ updateAccuracy(location);
+
+ // ease to new camera position with a linear interpolator
+ mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) locationUpdateDuration, false /*linear interpolator*/);
+ }
+
+ @Override
+ void invalidate() {
+ int[] mapPadding = mapboxMap.getPadding();
+ UiSettings uiSettings = mapboxMap.getUiSettings();
+ setX((uiSettings.getWidth() - getWidth() + mapPadding[0] - mapPadding[2]) / 2 + (contentPadding[0] - contentPadding[2]) / 2);
+ setY((uiSettings.getHeight() - getHeight() - mapPadding[3] + mapPadding[1]) / 2 + (contentPadding[1] - contentPadding[3]) / 2);
+ MyLocationView.this.invalidate();
+ }
+ }
+
+ private class MyLocationShowBehavior extends MyLocationBehavior {
+
+ @Override
+ void updateLatLng(@NonNull final Location location) {
+ if (latLng == null) {
+ // first location update
+ latLng = new LatLng(location);
+ locationUpdateTimestamp = SystemClock.elapsedRealtime();
+ }
+
+ // update LatLng location
+ previousLocation = latLng;
+ latLng = new LatLng(location);
+
+ // update LatLng direction
+ if (location.hasBearing()) {
+ gpsDirection = clamp(location.getBearing() - (float) mapboxMap.getCameraPosition().bearing);
+ setCompass(gpsDirection);
+ }
+
+ // update LatLng accuracy
+ updateAccuracy(location);
+
+ // calculate updateLatLng time + add some extra offset to improve animation
+ long previousUpdateTimeStamp = locationUpdateTimestamp;
+ locationUpdateTimestamp = SystemClock.elapsedRealtime();
+ long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1);
+
+ // calculate interpolated entity
+ interpolatedLocation = new LatLng((latLng.getLatitude() + previousLocation.getLatitude()) / 2, (latLng.getLongitude() + previousLocation.getLongitude()) / 2);
+
+ // animate changes
+ if (locationChangeAnimator != null) {
+ locationChangeAnimator.end();
+ locationChangeAnimator = null;
+ }
+
+ locationChangeAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+ locationChangeAnimator.setDuration((long) (locationUpdateDuration * 1.2));
+ locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this,
+ previousLocation, interpolatedLocation
+ ));
+ locationChangeAnimator.start();
+
+ // use interpolated location as current location
+ latLng = interpolatedLocation;
+ }
+
+ private float clamp(float direction) {
+ float diff = previousDirection - direction;
+ if (diff > 180.0f) {
+ direction += 360.0f;
+ } else if (diff < -180.0f) {
+ direction -= 360.f;
+ }
+ previousDirection = direction;
+ return direction;
+ }
+
+ @Override
+ void invalidate() {
+ PointF screenLocation = projection.toScreenLocation(latLng);
+ if (screenLocation != null) {
+ setX((screenLocation.x - getWidth() / 2));
+ setY((screenLocation.y - getHeight() / 2));
+ }
+ MyLocationView.this.invalidate();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
new file mode 100644
index 0000000000..9ae96ebf7b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
@@ -0,0 +1,146 @@
+package com.mapbox.mapboxsdk.maps.widgets;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IntRange;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+
+public class MyLocationViewSettings {
+
+ private MapView mapView;
+ private MyLocationView myLocationView;
+
+ //
+ // State
+ //
+
+ private boolean enabled;
+
+ //
+ // Foreground
+ //
+
+ private Drawable foregroundDrawable;
+ private Drawable foregroundBearingDrawable;
+
+ @ColorInt
+ private int foregroundTintColor;
+
+ //
+ // Background
+ //
+
+ private Drawable backgroundDrawable;
+ private int[] backgroundOffset = new int[4];
+
+ @ColorInt
+ private int backgroundTintColor;
+
+ //
+ // Accuracy
+ //
+
+ private int accuracyAlpha;
+
+ @ColorInt
+ private int accuracyTintColor;
+
+ //
+ // Padding
+ //
+
+ private int[] padding = new int[4];
+
+ public MyLocationViewSettings(MapView mapView, MyLocationView myLocationView) {
+ this.mapView = mapView;
+ this.myLocationView = myLocationView;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ myLocationView.setEnabled(enabled);
+ }
+
+ public void setForegroundDrawable(Drawable foregroundDrawable, Drawable foregroundBearingDrawable) {
+ this.foregroundDrawable = foregroundDrawable;
+ this.foregroundBearingDrawable = foregroundBearingDrawable;
+ myLocationView.setForegroundDrawables(foregroundDrawable, foregroundBearingDrawable);
+ }
+
+ public Drawable getForegroundDrawable() {
+ return foregroundDrawable;
+ }
+
+ public Drawable getForegroundBearingDrawable() {
+ return foregroundBearingDrawable;
+ }
+
+ public void setForegroundTintColor(@ColorInt int foregroundTintColor) {
+ this.foregroundTintColor = foregroundTintColor;
+ myLocationView.setForegroundDrawableTint(foregroundTintColor);
+ }
+
+ public int getForegroundTintColor() {
+ return foregroundTintColor;
+ }
+
+ public void setBackgroundDrawable(Drawable backgroundDrawable, int[] padding) {
+ this.backgroundDrawable = backgroundDrawable;
+ this.backgroundOffset = padding;
+ if (padding != null && padding.length == 4) {
+ myLocationView.setShadowDrawable(backgroundDrawable, padding[0], padding[1], padding[2], padding[3]);
+ } else {
+ myLocationView.setShadowDrawable(backgroundDrawable);
+ }
+ }
+
+ public Drawable getBackgroundDrawable() {
+ return backgroundDrawable;
+ }
+
+ public void setBackgroundTintColor(@ColorInt int backgroundTintColor) {
+ this.backgroundTintColor = backgroundTintColor;
+ myLocationView.setShadowDrawableTint(backgroundTintColor);
+ }
+
+ public int getBackgroundTintColor() {
+ return backgroundTintColor;
+ }
+
+ public int[] getBackgroundOffset() {
+ return backgroundOffset;
+ }
+
+ public void setPadding(int left, int top, int right, int bottom) {
+ padding = new int[]{left, top, right, bottom};
+ myLocationView.setContentPadding(padding);
+ mapView.invalidateContentPadding();
+ }
+
+ public int[] getPadding() {
+ return padding;
+ }
+
+ public int getAccuracyAlpha() {
+ return accuracyAlpha;
+ }
+
+ public void setAccuracyAlpha(@IntRange(from = 0, to = 255) int arruracyAlpha) {
+ this.accuracyAlpha = arruracyAlpha;
+ myLocationView.setAccuracyAlpha(arruracyAlpha);
+ }
+
+ public int getAccuracyTintColor() {
+ return accuracyTintColor;
+ }
+
+ public void setAccuracyTintColor(@ColorInt int accuracyTintColor) {
+ this.accuracyTintColor = accuracyTintColor;
+ myLocationView.setAccuracyTint(accuracyTintColor);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java
deleted file mode 100644
index 36e48488fa..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java
+++ /dev/null
@@ -1,757 +0,0 @@
-package com.mapbox.mapboxsdk.maps.widgets;
-
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.location.Location;
-import android.os.Build;
-import android.os.SystemClock;
-import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.mapbox.mapboxsdk.R;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.constants.MyBearingTracking;
-import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.Projection;
-
-import java.lang.ref.WeakReference;
-
-/**
- * UI element overlaid on a map to show the user's location.
- */
-public final class UserLocationView extends View {
-
- private MapboxMap mMapboxMap;
- private Projection mProjection;
-
- private boolean mShowMarker;
- private boolean mShowDirection;
- private boolean mShowAccuracy;
- private boolean mStaleMarker;
-
- private PointF mMarkerScreenPoint;
- private Matrix mMarkerScreenMatrix;
-
- private Paint mAccuracyPaintFill;
- private Paint mAccuracyPaintStroke;
- private Path mAccuracyPath;
- private RectF mAccuracyBounds;
-
- private Drawable mUserLocationDrawable;
- private RectF mUserLocationDrawableBoundsF;
- private Rect mUserLocationDrawableBounds;
-
- private Drawable mUserLocationBearingDrawable;
- private RectF mUserLocationBearingDrawableBoundsF;
- private Rect mUserLocationBearingDrawableBounds;
-
- private Drawable mUserLocationStaleDrawable;
- private RectF mUserLocationStaleDrawableBoundsF;
- private Rect mUserLocationStaleDrawableBounds;
-
- private Rect mDirtyRect;
- private RectF mDirtyRectF;
-
- private LatLng mMarkerCoordinate;
- private ValueAnimator mMarkerCoordinateAnimator;
- private float mGpsMarkerDirection;
- private float mCompassMarkerDirection;
- private ObjectAnimator mMarkerDirectionAnimator;
- private float mMarkerAccuracy;
- private ObjectAnimator mMarkerAccuracyAnimator;
-
- private LatLng mCurrentMapViewCoordinate;
- private double mCurrentBearing;
- private boolean mPaused = false;
- private Location mUserLocation;
- private UserLocationListener mUserLocationListener;
-
- private MapboxMap.OnMyLocationChangeListener mOnMyLocationChangeListener;
-
- @MyLocationTracking.Mode
- private int mMyLocationTrackingMode;
-
- @MyBearingTracking.Mode
- private int mMyBearingTrackingMode;
-
- // Compass data
- private MyBearingListener mBearingChangeListener;
-
- public UserLocationView(Context context) {
- super(context);
- initialize(context);
- }
-
- public UserLocationView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize(context);
- }
-
- public UserLocationView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initialize(context);
- }
-
- private void initialize(Context context) {
- // View configuration
- setEnabled(false);
- setWillNotDraw(false);
-
- // Layout params
- ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
- setLayoutParams(lp);
-
- // Setup sensors
- mBearingChangeListener = new MyBearingListener(context);
-
- // Setup the custom paint
- Resources resources = context.getResources();
- int accuracyColor = ContextCompat.getColor(context,R.color.my_location_ring);
-
- float density = resources.getDisplayMetrics().density;
- mMarkerCoordinate = new LatLng(0.0, 0.0);
- mMarkerScreenPoint = new PointF();
- mMarkerScreenMatrix = new Matrix();
-
- mAccuracyPaintFill = new Paint();
- mAccuracyPaintFill.setAntiAlias(true);
- mAccuracyPaintFill.setStyle(Paint.Style.FILL);
- mAccuracyPaintFill.setColor(accuracyColor);
- mAccuracyPaintFill.setAlpha((int) (255 * 0.25f));
-
- mAccuracyPaintStroke = new Paint();
- mAccuracyPaintStroke.setAntiAlias(true);
- mAccuracyPaintStroke.setStyle(Paint.Style.STROKE);
- mAccuracyPaintStroke.setStrokeWidth(0.5f * density);
- mAccuracyPaintStroke.setColor(accuracyColor);
- mAccuracyPaintStroke.setAlpha((int) (255 * 0.5f));
-
- mAccuracyPath = new Path();
- mAccuracyBounds = new RectF();
-
- mUserLocationDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location);
- mUserLocationDrawableBounds = new Rect(
- -mUserLocationDrawable.getIntrinsicWidth() / 2,
- -mUserLocationDrawable.getIntrinsicHeight() / 2,
- mUserLocationDrawable.getIntrinsicWidth() / 2,
- mUserLocationDrawable.getIntrinsicHeight() / 2);
- mUserLocationDrawableBoundsF = new RectF(
- -mUserLocationDrawable.getIntrinsicWidth() / 2,
- -mUserLocationDrawable.getIntrinsicHeight() / 2,
- mUserLocationDrawable.getIntrinsicWidth() / 2,
- mUserLocationDrawable.getIntrinsicHeight() / 2);
- mUserLocationDrawable.setBounds(mUserLocationDrawableBounds);
-
- mUserLocationBearingDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_bearing);
- mUserLocationBearingDrawableBounds = new Rect(
- -mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
- -mUserLocationBearingDrawable.getIntrinsicHeight() / 2,
- mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
- mUserLocationBearingDrawable.getIntrinsicHeight() / 2);
- mUserLocationBearingDrawableBoundsF = new RectF(
- -mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
- -mUserLocationBearingDrawable.getIntrinsicHeight() / 2,
- mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
- mUserLocationBearingDrawable.getIntrinsicHeight() / 2);
- mUserLocationBearingDrawable.setBounds(mUserLocationBearingDrawableBounds);
-
- mUserLocationStaleDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_stale);
- mUserLocationStaleDrawableBounds = new Rect(
- -mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
- -mUserLocationStaleDrawable.getIntrinsicHeight() / 2,
- mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
- mUserLocationStaleDrawable.getIntrinsicHeight() / 2);
- mUserLocationStaleDrawableBoundsF = new RectF(
- -mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
- -mUserLocationStaleDrawable.getIntrinsicHeight() / 2,
- mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
- mUserLocationStaleDrawable.getIntrinsicHeight() / 2);
- mUserLocationStaleDrawable.setBounds(mUserLocationStaleDrawableBounds);
- }
-
- public void setMapboxMap(MapboxMap mapboxMap) {
- mMapboxMap = mapboxMap;
- mProjection = mapboxMap.getProjection();
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (!mShowMarker) {
- return;
- }
-
- canvas.concat(mMarkerScreenMatrix);
-
- Drawable dotDrawable = mShowDirection ? mUserLocationBearingDrawable : mUserLocationDrawable;
- dotDrawable = mStaleMarker ? mUserLocationStaleDrawable : dotDrawable;
- // IMPORTANT also update in update()
- RectF dotBounds = mShowDirection ? mUserLocationBearingDrawableBoundsF : mUserLocationDrawableBoundsF;
- dotBounds = mStaleMarker ? mUserLocationStaleDrawableBoundsF : dotBounds;
-
- boolean willDraw = true;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN || !canvas.isHardwareAccelerated()) {
- willDraw = mShowAccuracy && !mStaleMarker && !canvas.quickReject(mAccuracyPath, Canvas.EdgeType.AA);
- }
- willDraw |= !canvas.quickReject(dotBounds, Canvas.EdgeType.AA);
-
- if (willDraw) {
- if (mShowAccuracy && !mStaleMarker) {
- canvas.drawPath(mAccuracyPath, mAccuracyPaintFill);
- canvas.drawPath(mAccuracyPath, mAccuracyPaintStroke);
- }
- dotDrawable.draw(canvas);
- }
- }
-
- public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
- mMyLocationTrackingMode = myLocationTrackingMode;
-
- if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && mUserLocation != null) {
- // center map directly if we have a location fix
- mMarkerCoordinate = new LatLng(mUserLocation.getLatitude(), mUserLocation.getLongitude());
- mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(mUserLocation)));
-
- // center view directly
- mMarkerScreenMatrix.reset();
- mMarkerScreenPoint = getMarkerScreenPoint();
- mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y);
- }
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
- toggleGps(enabled);
- }
-
- public void update() {
- if (isEnabled() && mShowMarker) {
- setVisibility(View.VISIBLE);
-
- mStaleMarker = isStale(mUserLocation);
-
- // compute new marker position
- // TODO add JNI method that takes existing pointf
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenPoint = getMarkerScreenPoint();
- mMarkerScreenMatrix.reset();
- mMarkerScreenMatrix.setTranslate(
- mMarkerScreenPoint.x,
- mMarkerScreenPoint.y);
-
- } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
- double bearing;
- if (mShowDirection) {
- bearing = mMyBearingTrackingMode == MyBearingTracking.COMPASS ? mBearingChangeListener.getCompassBearing() : mUserLocation.getBearing();
- } else {
- bearing = mMapboxMap.getCameraPosition().bearing;
- }
-
- if (mCurrentMapViewCoordinate == null) {
- mCurrentMapViewCoordinate = mMapboxMap.getCameraPosition().target;
- }
-
- // only update if there is an actual change
- if ((!mCurrentMapViewCoordinate.equals(mMarkerCoordinate)) || (!(mCurrentBearing == bearing))) {
- CameraPosition cameraPosition = new CameraPosition.Builder()
- .target(mMarkerCoordinate)
- .bearing(bearing)
- .build();
- mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 300, null);
- mMarkerScreenMatrix.reset();
- mMarkerScreenPoint = getMarkerScreenPoint();
- mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y);
-
- // set values for next check for actual change
- mCurrentMapViewCoordinate = mMarkerCoordinate;
- mCurrentBearing = bearing;
- }
- }
-
- // rotate so arrow in points to bearing
- if (mShowDirection) {
- if (mMyBearingTrackingMode == MyBearingTracking.COMPASS && mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenMatrix.preRotate((float)(mCompassMarkerDirection + mMapboxMap.getCameraPosition().bearing));
- } else if (mMyBearingTrackingMode == MyBearingTracking.GPS) {
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenMatrix.preRotate((float)(mGpsMarkerDirection + mMapboxMap.getCameraPosition().bearing));
- } else {
- mMarkerScreenMatrix.preRotate(mGpsMarkerDirection);
- }
- }
- }
-
- // adjust accuracy circle
- if (mShowAccuracy && !mStaleMarker) {
- mAccuracyPath.reset();
- mAccuracyPath.addCircle(0.0f, 0.0f,
- (float) (mMarkerAccuracy / mMapboxMap.getProjection().getMetersPerPixelAtLatitude(
- mMarkerCoordinate.getLatitude())),
- Path.Direction.CW);
-
- mAccuracyPath.computeBounds(mAccuracyBounds, false);
- mAccuracyBounds.inset(-1.0f, -1.0f);
- }
-
- // invalidate changed pixels
- if (mDirtyRect == null) {
- mDirtyRect = new Rect();
- mDirtyRectF = new RectF();
- } else {
- // the old marker location
- invalidate(mDirtyRect);
- }
-
- RectF dotBounds = mShowDirection ? mUserLocationBearingDrawableBoundsF : mUserLocationDrawableBoundsF;
- dotBounds = mStaleMarker ? mUserLocationStaleDrawableBoundsF : dotBounds;
- RectF largerBounds = mShowAccuracy && !mStaleMarker && mAccuracyBounds.contains(dotBounds)
- ? mAccuracyBounds : dotBounds;
- mMarkerScreenMatrix.mapRect(mDirtyRectF, largerBounds);
- mDirtyRectF.roundOut(mDirtyRect);
- invalidate(mDirtyRect); // the new marker location
- } else {
- setVisibility(View.INVISIBLE);
- }
- }
-
- public Location getLocation() {
- return mUserLocation;
- }
-
- /**
- * Enabled / Disable GPS location updates along with updating the UI
- *
- * @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
- */
- private void toggleGps(boolean enableGps) {
-
- LocationServices locationServices = LocationServices.getLocationServices(getContext());
-
- if (enableGps) {
- // Set an initial location if one available
- Location lastLocation = locationServices.getLastLocation();
- if (lastLocation != null) {
- setLocation(lastLocation);
- }
-
- if (mUserLocationListener == null) {
- mUserLocationListener = new UserLocationListener(this);
- }
-
- // Register for Location Updates
- locationServices.addLocationListener(mUserLocationListener);
- } else {
- // Disable location and user dot
- setLocation(null);
-
- // Deregister for Location Updates
- locationServices.removeLocationListener(mUserLocationListener);
- }
-
- locationServices.toggleGPS(enableGps);
- }
-
- public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
- mMyBearingTrackingMode = myBearingTrackingMode;
-
- if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
- mShowAccuracy = false;
- mShowDirection = true;
- mBearingChangeListener.onResume();
- } else {
- mBearingChangeListener.onPause();
- if (myBearingTrackingMode == MyBearingTracking.GPS) {
- mShowDirection = (mUserLocation != null) && mUserLocation.hasBearing();
- } else {
- mShowDirection = false;
- }
- }
- update();
- }
-
- private class MyBearingListener implements SensorEventListener {
-
- private SensorManager mSensorManager;
- private Sensor mAccelerometer;
- private Sensor mMagnetometer;
- private float[] mLastAccelerometer = new float[3];
- private float[] mLastMagnetometer = new float[3];
- private boolean mLastAccelerometerSet = false;
- private boolean mLastMagnetometerSet = false;
- private float[] mR = new float[9];
- private float[] mOrientation = new float[3];
- private float mCurrentDegree = 0f;
-
- // Controls the sensor update rate in milliseconds
- private static final int UPDATE_RATE_MS = 300;
-
- // Compass data
- private float mCompassBearing;
- private long mCompassUpdateNextTimestamp = 0;
-
- public MyBearingListener(Context context) {
- mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
- mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
- }
-
- public void onResume() {
- mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
- mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
- }
-
- public void onPause() {
- mSensorManager.unregisterListener(this, mAccelerometer);
- mSensorManager.unregisterListener(this, mMagnetometer);
- }
-
- public float getCompassBearing() {
- return mCurrentDegree;
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (mPaused) {
- return;
- }
-
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime < mCompassUpdateNextTimestamp) {
- return;
- }
-
- if (event.sensor == mAccelerometer) {
- System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
- mLastAccelerometerSet = true;
- } else if (event.sensor == mMagnetometer) {
- System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
- mLastMagnetometerSet = true;
- }
-
- if (mLastAccelerometerSet && mLastMagnetometerSet) {
- SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
- SensorManager.getOrientation(mR, mOrientation);
- float azimuthInRadians = mOrientation[0];
-
- mCompassBearing = (float) (Math.toDegrees(azimuthInRadians) + 360) % 360;
- if (mCompassBearing < 0) {
- // only allow positive degrees
- mCompassBearing += 360;
- }
-
- if (mCompassBearing > mCurrentDegree + 15 || mCompassBearing < mCurrentDegree - 15) {
- mCurrentDegree = mCompassBearing;
- setCompass(mCurrentDegree);
- }
- }
- mCompassUpdateNextTimestamp = currentTime + UPDATE_RATE_MS;
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // TODO add accuracy to the equiation
- }
- }
-
- private static class UserLocationListener implements LocationListener {
-
- private WeakReference<UserLocationView> mUserLocationView;
-
- public UserLocationListener(UserLocationView userLocationView) {
- mUserLocationView = new WeakReference<>(userLocationView);
- }
-
-
- /**
- * Callback method for receiving location updates from LocationServices.
- *
- * @param location The new Location data
- */
- @Override
- public void onLocationChanged(Location location) {
- UserLocationView locationView = mUserLocationView.get();
- if (locationView != null && !locationView.isPaused()) {
- locationView.setLocation(location);
- }
- }
- }
-
- private boolean isStale(Location location) {
- if (location != null && mMyBearingTrackingMode != MyBearingTracking.COMPASS) {
- long ageInNanos;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- ageInNanos = SystemClock.elapsedRealtimeNanos() -
- location.getElapsedRealtimeNanos();
- } else {
- ageInNanos = (System.currentTimeMillis() - location.getTime()) * 1000 * 1000;
- }
- final long oneMinuteInNanos = 60L * 1000 * 1000 * 1000;
- return ageInNanos > oneMinuteInNanos;
- } else {
- return false;
- }
- }
-
- // Handles location updates from GPS
- private void setLocation(Location location) {
- // if null we should hide the marker
- if (location == null) {
- mShowMarker = false;
- mShowDirection = false;
- mShowAccuracy = false;
-
- cancelAnimations();
-
- mUserLocation = null;
- return;
- }
-
- if (mMarkerCoordinateAnimator != null) {
- mMarkerCoordinateAnimator.end();
- mMarkerCoordinateAnimator = null;
- }
-
- if (mMarkerDirectionAnimator != null) {
- mMarkerDirectionAnimator.end();
- mMarkerDirectionAnimator = null;
- }
-
- if (mMarkerAccuracyAnimator != null) {
- mMarkerAccuracyAnimator.end();
- mMarkerAccuracyAnimator = null;
- }
-
- mShowMarker = true;
-
- LatLng previousCoordinate;
- if (mUserLocation == null) {
- previousCoordinate = new LatLng(location);
- } else {
- previousCoordinate = new LatLng(mUserLocation);
- }
-
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- // moving marker above map
- mMarkerCoordinateAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
- mMarkerCoordinateAnimator.setDuration(1000);
- mMarkerCoordinateAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(
- previousCoordinate, new LatLng(location)
- ));
- mMarkerCoordinateAnimator.start();
- mMarkerCoordinate = new LatLng(location);
- } else {
- // moving map under the tracker
- mMarkerCoordinate = new LatLng(location);
- }
-
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE && mMyBearingTrackingMode == MyBearingTracking.GPS) {
- // show GPS direction
- mShowDirection = location.hasBearing();
- if (mShowDirection) {
- if (mUserLocation != null && mUserLocation.hasBearing()) {
- mGpsMarkerDirection = mUserLocation.getBearing();
- }
- float oldDir = mGpsMarkerDirection;
- float newDir = location.getBearing();
- float diff = oldDir - newDir;
- if (diff > 180.0f) {
- newDir += 360.0f;
- } else if (diff < -180.0f) {
- newDir -= 360.f;
- }
- mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir);
- mMarkerDirectionAnimator.setDuration(1000);
- mMarkerDirectionAnimator.start();
- }
- } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW && mMyBearingTrackingMode == MyBearingTracking.GPS) {
- // always show north & rotate map below
- mShowDirection = true;
- mGpsMarkerDirection = 0;
- }
-
- mShowAccuracy = location.hasAccuracy();
- if (mShowAccuracy) {
- if (mUserLocation != null && mUserLocation.hasAccuracy()) {
- mMarkerAccuracy = mUserLocation.getAccuracy();
- }
- mMarkerAccuracyAnimator = ObjectAnimator.ofFloat(this, "accuracy", location.getAccuracy());
- mMarkerAccuracyAnimator.setDuration(1000);
- mMarkerAccuracyAnimator.start();
- }
-
- mUserLocation = location;
- updateOnNextFrame();
-
- if (mOnMyLocationChangeListener != null) {
- mOnMyLocationChangeListener.onMyLocationChange(location);
- }
- }
-
- // handles compass sensor updates
- private void setCompass(float bearing) {
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- // animate marker
- mShowDirection = true;
- float oldDir = mCompassMarkerDirection;
- float newDir = bearing;
- float diff = oldDir - newDir;
- if (diff > 180.0f) {
- newDir += 360.0f;
- } else if (diff < -180.0f) {
- newDir -= 360.f;
- }
- mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir);
- mMarkerDirectionAnimator.setDuration(1000);
- mMarkerDirectionAnimator.start();
- mCompassMarkerDirection = bearing;
-
- } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
- cancelAnimations();
- if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
- // always show north & change map direction
- mShowDirection = true;
- mGpsMarkerDirection = 0;
- mCompassMarkerDirection = 0;
- update();
- }
- }
- }
-
- void updateOnNextFrame() {
- mMapboxMap.invalidate();
- }
-
- public void onPause() {
- mPaused = true;
- mBearingChangeListener.onPause();
- cancelAnimations();
- toggleGps(false);
- }
-
- public void onResume() {
- mPaused = false;
- if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
- mBearingChangeListener.onResume();
- }
- if (isEnabled()) {
- toggleGps(true);
- }
- }
-
- public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) {
- mOnMyLocationChangeListener = listener;
- }
-
- // public for animator only
- public float getDirection() {
- if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
- return mCompassMarkerDirection;
- }
- return mGpsMarkerDirection;
- }
-
- // public for animator only
- public void setDirection(float direction) {
- if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
- mCompassMarkerDirection = direction % 360.0f;
- } else {
- mGpsMarkerDirection = direction % 360.0f;
- }
- updateOnNextFrame();
- }
-
- // public for animator only
- public float getAccuracy() {
- return mMarkerAccuracy;
- }
-
- // public for animator only
- public void setAccuracy(float accuracy) {
- mMarkerAccuracy = accuracy;
- updateOnNextFrame();
- }
-
- private class MarkerCoordinateAnimatorListener implements ValueAnimator.AnimatorUpdateListener {
-
- private double mFromLat;
- private double mFromLng;
- private double mToLat;
- private double mToLng;
-
- private MarkerCoordinateAnimatorListener(LatLng from, LatLng to) {
- mFromLat = from.getLatitude();
- mFromLng = from.getLongitude();
- mToLat = to.getLatitude();
- mToLng = to.getLongitude();
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float frac = animation.getAnimatedFraction();
- double latitude = mFromLat + (mToLat - mFromLat) * frac;
- double longitude = mFromLng + (mToLng - mFromLng) * frac;
- mMarkerCoordinate.setLatitude(latitude);
- mMarkerCoordinate.setLongitude(longitude);
- updateOnNextFrame();
- }
- }
-
- public void cancelAnimations() {
- if (mMarkerCoordinateAnimator != null) {
- mMarkerCoordinateAnimator.cancel();
- mMarkerCoordinateAnimator = null;
- }
-
- if (mMarkerDirectionAnimator != null) {
- mMarkerDirectionAnimator.cancel();
- mMarkerDirectionAnimator = null;
- }
-
- if (mMarkerAccuracyAnimator != null) {
- mMarkerAccuracyAnimator.cancel();
- mMarkerAccuracyAnimator = null;
- }
- }
-
- public boolean isPaused() {
- return mPaused;
- }
-
- public PointF getMarkerScreenPoint() {
- if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
- mMarkerScreenPoint = mProjection.toScreenLocation(mMarkerCoordinate);
- } else {
- int[] contentPadding = mMapboxMap.getPadding();
- mMarkerScreenPoint = new PointF(((getMeasuredWidth() + contentPadding[0] - contentPadding[2]) / 2)
- , ((getMeasuredHeight() - contentPadding[3] + contentPadding[1]) / 2));
- }
- return mMarkerScreenPoint;
- }
-}
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 85b3d619b8..e81c366dba 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
@@ -5,7 +5,7 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.Log;
-
+import com.mapbox.mapboxsdk.MapboxAccountManager;
import java.io.File;
/**
@@ -92,6 +92,10 @@ public class OfflineManager {
String cachePath = assetRoot + File.separator + DATABASE_NAME;
mDefaultFileSourcePtr = createDefaultFileSource(cachePath, assetRoot, DEFAULT_MAX_CACHE_SIZE);
+ if (MapboxAccountManager.getInstance() != null) {
+ setAccessToken(mDefaultFileSourcePtr, MapboxAccountManager.getInstance().getAccessToken());
+ }
+
// Delete any existing previous ambient cache database
deleteAmbientDatabase(context);
}
@@ -123,13 +127,24 @@ public class OfflineManager {
return instance;
}
- /*
+ /**
* Access token getter/setter
+ * @param accessToken
+ *
+ * @deprecated As of release 4.1.0, replaced by {@link MapboxAccountManager#start(Context, String)} ()}
*/
+ @Deprecated
public void setAccessToken(String accessToken) {
setAccessToken(mDefaultFileSourcePtr, accessToken);
}
+ /**
+ * Get Access Token
+ * @return Access Token
+ *
+ * @deprecated As of release 4.1.0, replaced by {@link MapboxAccountManager#getAccessToken()}
+ */
+ @Deprecated
public String getAccessToken() {
return getAccessToken(mDefaultFileSourcePtr);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
index e65a20f18e..48609a13bb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
@@ -13,17 +13,29 @@ public class OfflineRegionStatus {
@OfflineRegion.DownloadState private int downloadState = OfflineRegion.STATE_INACTIVE;
/**
- * The number of resources that have been fully downloaded and are ready for
- * offline access.
+ * The number of resources (inclusive of tiles) that have been fully downloaded
+ * and are ready for offline access.
*/
private long completedResourceCount = 0;
/**
- * The cumulative size, in bytes, of all resources that have been fully downloaded.
+ * The cumulative size, in bytes, of all resources (inclusive of tiles) that have
+ * been fully downloaded.
*/
private long completedResourceSize = 0;
/**
+ * The number of tiles that have been fully downloaded and are ready for
+ * offline access.
+ */
+ private long completedTileCount = 0;
+
+ /**
+ * The cumulative size, in bytes, of all tiles that have been fully downloaded.
+ */
+ private long completedTileSize = 0;
+
+ /**
* The number of resources that are known to be required for this region. See the
* documentation for `requiredResourceCountIsPrecise` for an important caveat
* about this number.
@@ -73,6 +85,14 @@ public class OfflineRegionStatus {
return completedResourceSize;
}
+ public long getCompletedTileCount() {
+ return completedTileCount;
+ }
+
+ public long getCompletedTileSize() {
+ return completedTileSize;
+ }
+
public long getRequiredResourceCount() {
return requiredResourceCount;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
index 736247bbac..b386ed6549 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
@@ -8,6 +8,7 @@ import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.location.Location;
import android.net.ConnectivityManager;
@@ -17,6 +18,7 @@ import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Build;
+import android.os.Handler;
import android.support.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -26,6 +28,7 @@ import android.view.WindowManager;
import com.mapbox.mapboxsdk.BuildConfig;
import com.mapbox.mapboxsdk.constants.GeoConstants;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.exceptions.TelemetryServiceNotConfiguredException;
import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.utils.MathUtils;
import org.json.JSONArray;
@@ -36,7 +39,6 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
-import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
@@ -47,6 +49,7 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
+import okhttp3.internal.Util;
/**
* Singleton control center for managing Telemetry Data.
@@ -58,11 +61,12 @@ public class MapboxEventManager {
private static MapboxEventManager mapboxEventManager = null;
+ private boolean initialized = false;
private boolean telemetryEnabled;
private final Vector<Hashtable<String, Object>> events = new Vector<>();
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
- private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
+ private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", MapboxConstants.MAPBOX_LOCALE);
private Context context = null;
private String accessToken = null;
@@ -81,7 +85,7 @@ public class MapboxEventManager {
private long mapboxSessionIdLastSet = 0;
private static long hourInMillis = 1000 * 60 * 60;
private static long flushDelayInitialInMillis = 1000 * 10; // 10 Seconds
- private static long flushDelayInMillis = 1000 * 60 * 2; // 2 Minutes
+ private static long flushDelayInMillis = 1000 * 60 * 3; // 3 Minutes
private static final int SESSION_ID_ROTATION_HOURS = 24;
private static MessageDigest messageDigest = null;
@@ -97,16 +101,26 @@ public class MapboxEventManager {
/**
* Internal setup of MapboxEventsManager. It needs to be called once before @link MapboxEventManager#getMapboxEventManager
- * <p/>
+ *
* This allows for a cleaner getMapboxEventManager() that doesn't require context and accessToken
*
* @param context The context associated with MapView
* @param accessToken The accessToken to load MapView
*/
public void initialize(@NonNull Context context, @NonNull String accessToken) {
+
+ Log.i(TAG, "Telemetry initialize() called...");
+
+ if (initialized) {
+ Log.i(TAG, "Mapbox Telemetry has already been initialized.");
+ return;
+ }
+
this.context = context.getApplicationContext();
this.accessToken = accessToken;
+ validateTelemetryServiceConfigured();
+
// Setup Message Digest
try {
messageDigest = MessageDigest.getInstance("SHA-1");
@@ -114,9 +128,13 @@ public class MapboxEventManager {
Log.w(TAG, "Error getting Encryption Algorithm: " + e);
}
+ // Create Initial Session Id
+ rotateSessionId();
+
SharedPreferences prefs = context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE);
// Determine if Telemetry Should Be Enabled
+ Log.i(TAG, "Right before Telemetry set enabled in initialized()");
setTelemetryEnabled(prefs.getBoolean(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED, true));
// Load / Create Vendor Id
@@ -132,9 +150,6 @@ public class MapboxEventManager {
editor.commit();
}
- // Create Initial Session Id
- rotateSessionId();
-
// Get DisplayMetrics Setup
displayMetrics = new DisplayMetrics();
((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
@@ -160,6 +175,8 @@ public class MapboxEventManager {
// Build User Agent
if (TextUtils.equals(userAgent, BuildConfig.MAPBOX_EVENTS_USER_AGENT_BASE) && !TextUtils.isEmpty(appName) && !TextUtils.isEmpty(versionName)) {
userAgent = appName + "/" + versionName + "/" + versionCode + " " + userAgent;
+ // Ensure that only ASCII characters are sent
+ userAgent = Util.toHumanReadableAscii(userAgent);
}
} catch (Exception e) {
@@ -169,6 +186,8 @@ public class MapboxEventManager {
// Register for battery updates
IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
batteryStatus = context.registerReceiver(null, iFilter);
+
+ initialized = true;
}
/**
@@ -183,6 +202,24 @@ public class MapboxEventManager {
return mapboxEventManager;
}
+ // Checks that TelemetryService has been configured by developer
+ private void validateTelemetryServiceConfigured() {
+ try {
+ // Check Implementing app's AndroidManifest.xml
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SERVICES);
+ if (packageInfo.services != null) {
+ for (ServiceInfo service : packageInfo.services) {
+ if (TextUtils.equals("com.mapbox.mapboxsdk.telemetry.TelemetryService", service.name)) {
+ return;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(MapboxConstants.TAG, "Error checking for Telemetry Service Config: " + e);
+ }
+ throw new TelemetryServiceNotConfiguredException();
+ }
+
public static String generateCreateDate() {
return dateFormat.format(new Date());
}
@@ -196,6 +233,7 @@ public class MapboxEventManager {
* @param telemetryEnabled True to start telemetry, false to stop it
*/
public void setTelemetryEnabled(boolean telemetryEnabled) {
+ Log.i(TAG, "setTelemetryEnabled(); this.telemetryEnabled = " + this.telemetryEnabled + "; telemetryEnabled = " + telemetryEnabled);
if (this.telemetryEnabled == telemetryEnabled) {
Log.d(TAG, "No need to start / stop telemetry as it's already in that state.");
return;
@@ -207,8 +245,33 @@ public class MapboxEventManager {
context.startService(new Intent(context, TelemetryService.class));
// Make sure Ambient Mode is started at a minimum
- if (LocationServices.getLocationServices(context).isGPSEnabled()) {
- LocationServices.getLocationServices(context).toggleGPS(false);
+ if (LocationServices.getLocationServices(context).areLocationPermissionsGranted()) {
+ Log.i(TAG, "Permissions are good, see if GPS is enabled and if not then setup Ambient.");
+ if (LocationServices.getLocationServices(context).isGPSEnabled()) {
+ LocationServices.getLocationServices(context).toggleGPS(false);
+ }
+ } else {
+ // Start timer that checks for Permissions
+ Log.i(TAG, "Permissions are not good. Need to do some looping to check on stuff.");
+
+ final Handler permsHandler = new Handler();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ if (LocationServices.getLocationServices(context).areLocationPermissionsGranted()) {
+ Log.i(TAG, "Permissions finally granted, so starting Ambient if GPS isn't already enabled");
+ // Start Ambient
+ if (LocationServices.getLocationServices(context).isGPSEnabled()) {
+ LocationServices.getLocationServices(context).toggleGPS(false);
+ }
+ } else {
+ // Restart Handler
+ Log.i(TAG, "Permissions not granted yet... let's try again in 30 seconds");
+ permsHandler.postDelayed(this, 1000 * 30);
+ }
+ }
+ };
+ permsHandler.postDelayed(runnable, 1000 * 10);
}
// Manage Timer Flush
@@ -381,7 +444,7 @@ public class MapboxEventManager {
*/
private void rotateSessionId() {
long now = System.currentTimeMillis();
- if (now - mapboxSessionIdLastSet > (SESSION_ID_ROTATION_HOURS * hourInMillis)) {
+ if ((TextUtils.isEmpty(mapboxSessionId)) || (now - mapboxSessionIdLastSet > (SESSION_ID_ROTATION_HOURS * hourInMillis))) {
mapboxSessionId = UUID.randomUUID().toString();
mapboxSessionIdLastSet = System.currentTimeMillis();
}
@@ -524,7 +587,7 @@ public class MapboxEventManager {
@Override
protected Void doInBackground(Void... voids) {
- if (events.size() < 1) {
+ if (events.isEmpty()) {
Log.d(TAG, "No events in the queue to send so returning.");
return null;
}
@@ -533,7 +596,10 @@ public class MapboxEventManager {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnected()) {
- Log.w(TAG, "Not connected to network, so returning without attempting to send events");
+ Log.w(TAG, "Not connected to network, so empty events cache and return without attempting to send events");
+ // Make sure that events don't pile up when Offline
+ // and thus impact available memory over time.
+ events.removeAllElements();
return null;
}
@@ -642,12 +708,13 @@ public class MapboxEventManager {
Response response = client.newCall(request).execute();
Log.d(TAG, "response code = " + response.code() + " for events " + events.size());
- // Reset Events
- // ============
- events.removeAllElements();
} catch (Exception e) {
Log.e(TAG, "FlushTheEventsTask borked: " + e);
e.printStackTrace();
+ } finally {
+ // Reset Events
+ // ============
+ events.removeAllElements();
}
return null;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
index a35a87eb09..c18da41e4b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
@@ -37,7 +37,7 @@ public class TelemetryLocationReceiver extends BroadcastReceiver {
* 10 seconds that the system allows before considering the receiver to
* be blocked and a candidate to be killed). You cannot launch a popup dialog
* in your implementation of onReceive().
- * <p/>
+ *
* <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
* then the object is no longer alive after returning from this
* function.</b> This means you should not perform any operations that
@@ -47,7 +47,7 @@ public class TelemetryLocationReceiver extends BroadcastReceiver {
* {@link Context#bindService(Intent, ServiceConnection, int)}. If you wish
* to interact with a service that is already running, you can use
* {@link #peekService}.
- * <p/>
+ *
* <p>The Intent filters used in {@link Context#registerReceiver}
* and in application manifests are <em>not</em> guaranteed to be exclusive. They
* are hints to the operating system about how to find suitable recipients. It is
@@ -63,7 +63,7 @@ public class TelemetryLocationReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Location location = (Location)intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
if (location != null) {
- Log.d(TAG, "location received = " + location);
+// Log.d(TAG, "location received = " + location);
MapboxEventManager.getMapboxEventManager().addLocationEvent(location);
} else {
Log.d(TAG, "location NOT received");
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
index 0db75c92f4..008f355f29 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
@@ -25,7 +25,7 @@ public class TelemetryService extends Service {
* {@link IBinder} is usually for a complex interface
* that has been <a href="{@docRoot}guide/components/aidl.html">described using
* aidl</a>.
- * <p/>
+ *
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about the main thread can be found in
@@ -93,19 +93,17 @@ public class TelemetryService extends Service {
* Called by the system every time a client explicitly starts the service by calling
* {@link Context#startService}, providing the arguments it supplied and a
* unique integer token representing the start request. Do not call this method directly.
- * <p/>
+ *
* <p>For backwards compatibility, the default implementation calls
* {@link #onStart} and returns either {@link #START_STICKY}
* or {@link #START_STICKY_COMPATIBILITY}.
- * <p/>
+ * </p>
* <p>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to handle the older {@link #onStart}
* callback in that case. The <code>handleCommand</code> method is implemented by
* you as appropriate:
- * <p/>
- * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
- * start_compatibility}
- * <p/>
+ * </p>
+ *
* <p class="caution">Note that the system calls this on your
* service's main thread. A service's main thread is the same
* thread where UI operations take place for Activities running in the
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
new file mode 100644
index 0000000000..495393c258
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
@@ -0,0 +1,93 @@
+package com.mapbox.mapboxsdk.utils;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.support.annotation.AnimatorRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.View;
+
+public class AnimatorUtils {
+
+ public static void animate(@NonNull final View view, @AnimatorRes int animatorRes, @Nullable OnAnimationEndListener listener) {
+ animate(view, animatorRes, -1, listener);
+ }
+
+ public static void animate(final View view, @AnimatorRes int animatorRes, int duration, @Nullable final OnAnimationEndListener listener) {
+ if (view == null) {
+ return;
+ }
+
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ Animator animator = AnimatorInflater.loadAnimator(view.getContext(), animatorRes);
+ if (duration != -1) {
+ animator.setDuration(duration);
+ }
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ if (listener != null) {
+ listener.onAnimationEnd();
+ }
+ }
+ });
+ animator.setTarget(view);
+ animator.start();
+ }
+
+ public static void animate(@NonNull final View view, @AnimatorRes int animatorRes) {
+ animate(view, animatorRes, -1);
+ }
+
+ public static void animate(@NonNull final View view, @AnimatorRes int animatorRes, int duration) {
+ animate(view, animatorRes, duration, null);
+ }
+
+ 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);
+ rotateAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
+ rotateAnimator.start();
+ }
+
+ public static void alpha(@NonNull final View convertView, float alpha, @Nullable final OnAnimationEndListener listener) {
+ convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(convertView, View.ALPHA, convertView.getAlpha(), alpha);
+ rotateAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ convertView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ convertView.setLayerType(View.LAYER_TYPE_NONE, null);
+ if (listener != null) {
+ listener.onAnimationEnd();
+ }
+ }
+ });
+ rotateAnimator.start();
+ }
+
+ public static void alpha(@NonNull final View convertView, float alpha) {
+ alpha(convertView, alpha, null);
+ }
+
+ 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
new file mode 100644
index 0000000000..a0de07c5f1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -0,0 +1,90 @@
+package com.mapbox.mapboxsdk.utils;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.util.TypedValue;
+import android.widget.ImageView;
+
+import com.mapbox.mapboxsdk.R;
+
+public class ColorUtils {
+
+ /**
+ * Returns a color integer associated as primary color from a theme based on a {@link Context}.
+ *
+ * @param context The context used to style the color attributes.
+ * @return The primary color value of current theme in the form 0xAARRGGBB.
+ */
+ @ColorInt
+ public static int getPrimaryColor(@NonNull Context context) {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
+ return typedValue.data;
+ }
+
+ /**
+ * Returns a color integer associated as primary dark color from a theme based on a {@link Context}.
+ *
+ * @param context The context used to style the color attributes.
+ * @return The primary dark color value of current theme in the form 0xAARRGGBB.
+ */
+ @ColorInt
+ public static int getPrimaryDarkColor(@NonNull Context context) {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
+ return typedValue.data;
+ }
+
+ /**
+ * Returns a color integer associated as accent color from a theme based on a {@link Context}.
+ *
+ * @param context The context used to style the color attributes.
+ * @return The accent color value of current theme in the form 0xAARRGGBB.
+ */
+ @ColorInt
+ public static int getAccentColor(@NonNull Context context) {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ theme.resolveAttribute(R.attr.colorAccent, typedValue, true);
+ return typedValue.data;
+ }
+
+ /**
+ * Returns a color state list associated with a theme based on a {@link Context}
+ *
+ * @param color The color used for tinting.
+ * @return A ColorStateList object containing the primary color of a theme
+ */
+ @NonNull
+ public static ColorStateList getSelector(@ColorInt int color) {
+ return new ColorStateList(
+ new int[][]{
+ new int[]{android.R.attr.state_pressed},
+ new int[]{}
+ },
+ new int[]{
+ color,
+ color
+ }
+ );
+ }
+
+ /**
+ * Set a color tint list to the {@link Drawable} of an {@link ImageView}.
+ *
+ * @param imageView The view to set the default tint list.
+ * @param tintColor The color to tint.
+ */
+ public static void setTintList(@NonNull ImageView imageView, @ColorInt int tintColor) {
+ Drawable originalDrawable = imageView.getDrawable();
+ Drawable wrappedDrawable = DrawableCompat.wrap(originalDrawable);
+ DrawableCompat.setTintList(wrappedDrawable, getSelector(tintColor));
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
index 922fb11868..a92999c0d5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
@@ -27,7 +27,7 @@ public class MathUtils {
/**
* Constrains value to the given range (including min, excluding max) via modular arithmetic.
*
- * Same formula as used in Core GL (math.hpp)
+ * Same formula as used in Core GL (wrap.hpp)
* std::fmod((std::fmod((value - min), d) + d), d) + min;
*
* @param value Value to wrap
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/overview.html b/platform/android/MapboxGLAndroidSDK/src/main/java/overview.html
index 951b8d8e75..f218b3ccf9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/overview.html
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/overview.html
@@ -1,9 +1,11 @@
<html>
<body>
+<p>
An open source OpenGL-based vector map solution for Android with full styling capabilities.
-<p/>
+</p>
+<p>
For more information, check out <a href="https://www.mapbox.com/android-sdk/">our online overview</a>.
-<p/>
+</p>
<!--TODO: Need an Android image-->
<!--<img src="https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png"/>-->
<!--<h2>Changelog</h2>
@@ -14,4 +16,4 @@ Initial preview release.
<h3>0.1.0</h3>
<p>Initial beta release.</p>-->
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_bearing.png
new file mode 100755
index 0000000000..c93fa4781a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_bearing.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_normal.png
new file mode 100755
index 0000000000..120b7dd612
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_mylocationview_normal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png
deleted file mode 100755
index 1ae8d541af..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png
deleted file mode 100755
index 8ecaffa2e8..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png
deleted file mode 100755
index 0d599c01fa..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_bearing.png
new file mode 100755
index 0000000000..0d7d89a8b4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_bearing.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_normal.png
new file mode 100755
index 0000000000..831ef1acf4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_mylocationview_normal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png
deleted file mode 100755
index 542cd25e22..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png
deleted file mode 100755
index 429f03f648..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png
deleted file mode 100755
index 6613c41153..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_bearing.png
new file mode 100755
index 0000000000..1056d617e9
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_bearing.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_normal.png
new file mode 100755
index 0000000000..37b1f7adbf
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_mylocationview_normal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png
deleted file mode 100755
index ca1f1fe630..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png
deleted file mode 100755
index 1b88f9f489..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png
deleted file mode 100755
index 7af3789ff0..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_bearing.png
new file mode 100755
index 0000000000..1ff2590606
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_bearing.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_normal.png
new file mode 100755
index 0000000000..520b85eff7
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_mylocationview_normal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png
deleted file mode 100755
index 6f175df168..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png
deleted file mode 100755
index f4bb454a06..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png
deleted file mode 100755
index f1d2f2eca0..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_bearing.png
new file mode 100755
index 0000000000..671c33a08e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_bearing.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_normal.png
new file mode 100755
index 0000000000..f9f4265d2a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_mylocationview_normal.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png
deleted file mode 100755
index d43541ac3c..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png
deleted file mode 100755
index a8cccbb3e2..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png
deleted file mode 100755
index 33e952391f..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_mylocationview_background.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_mylocationview_background.xml
new file mode 100644
index 0000000000..e1df60788e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_mylocationview_background.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <solid android:color="@color/white" />
+
+ <size
+ android:width="@dimen/my_locationview_outer_circle"
+ android:height="@dimen/my_locationview_outer_circle" />
+</shape> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
index 04b7033282..9799487f12 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
@@ -29,7 +29,7 @@
android:src="@drawable/ic_info_outline_24dp_selector"
android:background="@drawable/bg_default_selector"/>
- <com.mapbox.mapboxsdk.maps.widgets.UserLocationView
+ <com.mapbox.mapboxsdk.maps.widgets.MyLocationView
android:id="@+id/userLocationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index a6e1f044c8..66ddd251a5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -1,23 +1,47 @@
<resources>
<!-- these are public -->
<declare-styleable name="MapView">
+
+ <!--Configuration-->
+ <attr name="access_token" format="string" />
+ <attr name="style_url" format="string" />
+
+ <!--Camera-->
<attr name="center_longitude" format="float" />
<attr name="center_latitude" format="float" />
<attr name="zoom" format="float" />
- <attr name="zoom_max" format="float" />
- <attr name="zoom_min" format="float" />
<attr name="direction" format="float" />
<attr name="tilt" format="float" />
+
+ <!--Zoom-->
+ <attr name="zoom_max" format="float" />
+ <attr name="zoom_min" format="float" />
+
+ <!--Gestures-->
<attr name="zoom_enabled" format="boolean" />
<attr name="scroll_enabled" format="boolean" />
<attr name="rotate_enabled" format="boolean" />
<attr name="tilt_enabled" format="boolean" />
- <attr name="zoom_controls_enabled" format="boolean" />
<attr name="debug_active" format="boolean" />
- <attr name="style_url" format="string" />
- <attr name="access_token" format="string" />
- <attr name="style_classes" format="string" />
+
+ <!--UI-Controls-->
+ <attr name="zoom_controls_enabled" format="boolean" />
+
+ <!--MyLocation-->
<attr name="my_location_enabled" format="boolean" />
+ <attr name="my_location_foreground" format="reference" />
+ <attr name="my_location_foreground_bearing" format="reference" />
+ <attr name="my_location_foreground_tint" format="color" />
+ <attr name="my_location_background" format="reference" />
+ <attr name="my_location_background_tint" format="color" />
+ <attr name="my_location_background_left" format="dimension" />
+ <attr name="my_location_background_top" format="dimension" />
+ <attr name="my_location_background_right" format="dimension" />
+ <attr name="my_location_background_bottom" format="dimension" />
+ <attr name="my_location_accuracy_tint" format="color" />
+ <attr name="my_location_accuracy_alpha" format="integer" />
+
+ <!--Compass-->
<attr name="compass_enabled" format="boolean" />
<attr name="compass_gravity">
<flag name="top" value="0x30" />
@@ -39,6 +63,8 @@
<attr name="compass_margin_top" format="dimension" />
<attr name="compass_margin_right" format="dimension" />
<attr name="compass_margin_bottom" format="dimension" />
+
+ <!--Logo-->
<attr name="logo_gravity">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
@@ -61,6 +87,7 @@
<attr name="logo_margin_bottom" format="dimension" />
<attr name="logo_enabled" format="boolean" />
+ <!--Attribution-->
<attr name="attribution_gravity">
<flag name="top" value="0x30" />
<flag name="bottom" value="0x50" />
@@ -82,5 +109,6 @@
<attr name="attribution_margin_right" format="dimension" />
<attr name="attribution_margin_bottom" format="dimension" />
<attr name="attribution_enabled" format="boolean" />
+ <attr name="attribution_tint" format="color" />
</declare-styleable>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
index 97d29c7d45..63f739c30c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <color name="white">#FFFFFF</color>
+ <color name="white">#F9F9F9</color>
<color name="black">#000000</color>
<color name="gray">#7D7F80</color>
<color name="gray_light">#EEEEEE</color>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index 5167ecf936..d6cca7090f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -9,4 +9,6 @@
<dimen name="ten_dp">10dp</dimen>
<dimen name="sixteen_dp">16dp</dimen>
<dimen name="seventy_six_dp">76dp</dimen>
+ <dimen name="my_locationview_size">64dp</dimen>
+ <dimen name="my_locationview_outer_circle">18dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/integers.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/integers.xml
new file mode 100644
index 0000000000..3727365659
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="style_version">9</integer>
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
index 1f3cd8c4e3..becbcce0b0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -11,10 +11,11 @@
<string name="infoWindowAddress">Address</string>
<!-- these are public -->
- <string name="style_mapbox_streets">mapbox://styles/mapbox/streets-v8</string>
+ <!-- {@deprecated Use Style.getXStyleUrl(int version) instead.} -->
+ <string name="style_mapbox_streets">mapbox://styles/mapbox/streets-v9</string>
<string name="style_emerald">mapbox://styles/mapbox/emerald-v8</string>
- <string name="style_light">mapbox://styles/mapbox/light-v8</string>
- <string name="style_dark">mapbox://styles/mapbox/dark-v8</string>
- <string name="style_satellite">mapbox://styles/mapbox/satellite-v8</string>
- <string name="style_satellite_streets">mapbox://styles/mapbox/satellite-hybrid-v8</string>
+ <string name="style_light">mapbox://styles/mapbox/light-v9</string>
+ <string name="style_dark">mapbox://styles/mapbox/dark-v9</string>
+ <string name="style_satellite">mapbox://styles/mapbox/satellite-v9</string>
+ <string name="style_satellite_streets">mapbox://styles/mapbox/satellite-hybrid-v9</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
index 9ad12f76ad..a46f58ae80 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
@@ -4,7 +4,6 @@
<!-- these are public -->
<style name="AttributionAlertDialogStyle" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:textColorPrimary">@android:color/white</item>
- <item name="android:background">@color/mapbox_blue</item>
</style>
</resources> \ No newline at end of file