Merge release-ios-v3.6.0-android-v5.1.0 to master (#9170)

* [android] Update release script to support CircleCI builds (#8950)

* update release script to trigger builds on circleci now

* update release script to trigger builds on circleci now

* [core] When a layer is added, reload its source's tiles

* [android] - keep observer when timeout occurs, make observer param nullable, fixup log messages (#8919)

* [android] - avoid crashing when deleting already deleted region (#8920)

* [android] - update LOST to 2.3.0 (#8872)

* [android] - update proguard config, allow debug mimification, update OkHttp to latest version (#8944)

* [core, android, ios, macos, qt] v10 default styles

Upgraded from v9 default styles to v10 wherever the developer expects to get the latest and greatest, as well as in a couple tests where it may be beneficial to ensure that we can handle a two-digit version number in the style URL.

Cherry-picked from ed54849e99.

* [ios, macos] Updated documented default style version

MGLStyleDefaultVersion is just for Streets now. Deleted style version documentation tests because not all styles are on the same version.

Cherry-picked from ca97dd8cf4.

* [ios, macos] Undeprecated unversioned style URL factory methods

Undeprecated the unversioned style URL factory methods in MGLStyle for consistency with the Android and Qt SDKs. Added warnings about using them with the runtime styling API.

Refactored mbgl::util::default_styles to track different versions for different styles.

Cherry-picked from 9e384b78fb.

* [core, android, ios, macos] Added Traffic Day/Night to default styles

The Styles API section of the Mapbox API Documentation site now lists Traffic Day v2 and Traffic Night v2, so this change adds those styles to all the places where styles are listed.

Also switched iosapp and macosapp to unversioned style factory methods since MGLStyleDefaultVersion is no longer applicable for all styles.

Cherry-picked from 4d6f54553d.

* [android] Release android-v5.1.0-beta.2 (#8976)

* [android] url getter on sources

* [android] fix ui test filter in makefile

* [android] - build SNAPSHOT from release branch (#8958)

* [android] - update changelog for 5.1.0-beta.2

* [android] - bump version number

* [android] - Camera change listener v2.0

* [core] allow filesource url transform reset

* [android] Update attribution wordmark (#8774)

* Update wordmark on android

* Moved attribution i icon to the right of mapbox word (in mapview preview image)

* update padding and margin

* [android] update hardcoded branch name

* revert version to 5.1.0-SNAPSHOT

* [android] - MarkerView deselect events with OnMarkerViewClickListener integration (#8996)

* [android] - publish SNAPSHOT from release 5.1.0 branch (#8995)

* [ios, macos] edited identity interpolation mode documentation (#8657)

* [ios, macos] Factored out tile URL template guide

Factored out redundant tile URL template documentation from the MGLRasterSource and MGLVectorSource documentation into a jazzy guide. This documentation used to live in one place, on a method on MGLTileSource, but that method had to be moved to MGLTileSource’s concrete subclasses. A jazzy guide is easier to link to, in any case.

* [ios] Telemetry button in modal view controllers (#9027)

Fixes #8980.

* [android] - bump tools and support lib version due to SNAPSHOT dependencies (#9046)

* [android] - bump tools and support lib version for SNAPSHOT dependencies

* revert unsupported Circle CI build tools version

* [core] Make destructor virtual to avoid object splicing during destruction

* [core] add error for non-virtual destructor deletes + add virtual dtors

* [android] -  remove marker from selected markers when removing marker from annotation manager. (#9047)

* Observe layout guides (#7716)

* [ios] observe layout guides

* [ios] update changelog

* [ios, macos] Change == to = in style function initializers

* [ios] Add annotation view initializer with annotation and reuse id (#9029)

* [ios] Remove annotation view from container view when annotation removed (#9025)

The annotation container view keeps an array of annotation views that is separate from the array of subviews that is a property of the UIView parent class. This removes an annotation view from that container view array when the associated annotation is removed. This avoids issue related to previously removed annotation views continuing to be involved in map view logic around annotation view selection due to taps.

* [android] - correct bearing conversion when animating the map with jumpTo, easeTo and animateTo. (#9050)

* [ios, macos] Updated `maximumZoomLevel` description, cherry-picked #8818 (#8842)

Cherry-picked from a3e4e67ea6.

* [ios] Updated podspecs and changelog for v3.5.3 (#8870)

Cherry-picked from 25c19902a2.

* [ios] Update podspecs and changelog for iOS v3.5.4

Cherry-picked from db7bb509e9.

* [ios, macos] Updated changelogs

* [ios, macos] changed TRUE -> 'true' (#9059) fixes #9056

* [ios, macos] Light property implementation in MGLStyle (#9043)

* [ios, macos] Add MGLLight to MGLStyle

* [ios, macos] Implement Objc bindings for Light object

* [ios, macos] Remove rawLight from MGLLight and re-implement it as value class

* [ios, macos] Fix build on macos

* [ios, macos] Add MGLLight documentation, Move MGLLightPosition to MGLLight

* [ios, macos] Add MGLLight tests.

* [ios, macos] Update changelogs

* [ios, macos] Fix misspelling

* [ios, macos] Fix MGLLightAnchor enum property names

* [ios, macos] Update documentation. Improve varialble naming.

* [ios, macos] Rename MGLLightPosition to MGLSphericalPosition

* [ios, macos] Update data types of MGLSphericalPosition

* [android] - horizontally rotated in snapshot (#9083)

* Cherry-pick arabic text to release branch v3.6.0 (#9071)

* [core] Throttle tiles to redo symbol placement at most once every 300ms.
Fixes issue #8435 and prepares for pitch-scaling changes in issue #8967.

* [core] Disable letter-spacing for Arabic labels (issue #9057)

* [ios,macos] multipolygon coordinate (#8713)

* [ios] MGLMultiPolygon's coordinate property implemented

* [ios,macos] Add polylabalel to project config

* [ios,macos] Change coordinate property for MGLPolyline,MGLPolygon,MGLMultiPolygon

* [macos] Change project configuration to support polilabel

* [ios,macos] Add MGLLocationCoordinate2DFromPoint

* [ios, macos] Update changelogs

* [ios, macos] remove unnecesary variables

* [ios, macos] Add radians conversions

* [ios, macos] Add coordinate calc to MGLPolyline

* [ios, macos] Move radian fuctions to MGLGeometry_Private.h

* [ios, macos] Fix code style

* [ios, macos] Fix code indentation

* [ios, macos] Fix radian per meters constant

* [ios, macos] Add test scenarios to testPolyline

* [ios, macos] Fix test accuracy

* [ios, macos] More robust Streets localization

Added Arabic, Portuguese, and Simplified Chinese to the list of languages with specialized fields in the Mapbox Streets source.

Rely on NSBundle to select the most appropriate locale based on the user’s preferred languages.

* [ios] Fallback to Mapbox.bundle as the framework bundle (#9074)

Fixes an issue where localizations could not be found when using static builds.

Throws exception if our bundle can't be found.

* [ios] Move image resources to an asset catalog & switch to PDFs

* [ios, macos] Updated changelogs

Reorganized the changelogs with a new packaging section. Added blurbs about #9062, #8713, #9060, and #9031.

* [ios] Update pods spec for iOS v3.6.0-beta.1

* [macos] Enable View ‣ Traffic Night

Enable the View ‣ Traffic Night menu item and check it when that style is active.

* [android] - stop location updates when toggle MyLocationView state (#9099)

* [android] - LatLngBounds bearing default value (#9102)

* [ios, macos] Fix MGLLight.achor to accept style functions

* [ios] Fix annotation initializers for subclasses of MGLAnnotationView (#9104)

Use a common init function in both of the provided initializers so that subclasses of `MGLAnnotationView` written in Swift don't need to override `init(annotation, reuseIdentifier)`

* [ios] Moved `MGLLight` in jazzy table of contents (#9111)

* [android] - logo placement for creating a Mapview programatically (#9094)

* [android] - Correct logo placement for creating a Mapview programatically, fixup non default placements

* Fixed NIGHTY_TWO_DP typo to NINETY_TWO_DP

* [android] - add binding support for Light (#9013)

* [android] Update Lost to final version 3.0.0 (#9112)

* update lost to final version 3.0.0

* bump MAS version to 2.1.1

* [android] - convert dp to pixels when getting meters per pixel at. (#9048)

* Release Android v5.1.0-beta.3 (#9115)

* [android] - Changelog update for Android release v5.1.0-beta.3

* update CI & version

* reset release properties

* [android] - harden orientation changes (#9128)

* [ios] Remove filter of single metric event

* [ios] remove layout guide observers

* Migrate to GL JS–powered feedback form (#9078)

* [ios, macos] Updated feedback URL

* [ios, macos] Add referrer, heading, pitch to feedback URL

* [ios, macos] Updated changelogs for feedback changes

* [ios] Vary referrer by platform

* [android] - javadoc update for 5.1.0 release (#9138)

* [android] - javadoc update for 5.1.0 release

* oxford comma

* Grammar/spelling tweaks

* grammar tweak

* grammar tweak

* Grammar tweaks

* Grammar tweaks

* [android] fix missing access token variable issue (#9151)

* [ios] Update pods spec for iOS v3.6.0-beta.2

* [android] Cherry picking 9133 (#9145)

* [android] Fix tracking mode + camera race condition (#9133)

* [android] fix tracking mode + camera race condition

* fix resetTrackingModesIfRequired bug (comparing current camera position with target camera position

* cherry pick #9133 and update CHANGELOG

* add null check to prevent null pointer exception

* add null check in custom location engine activity to prevent null pointer exception (#9159)

* [core] Make TransformState LatLngBounds optional

* [ios] Make annotation view rotation alignment configurable (#9147)

This commit adds `rotatesWithMap` property on `MGLAnnotationView`. This
property, when set to `YES` fixes the annotation to a map such that view
follows map's rotation angle. This is useful when user wants to display
rotation-dependent annotations (e.g. sector lights).

* [android] - validate if gestures should execute (#9173)
This commit is contained in:
Tobrun
2017-06-02 23:41:14 +02:00
committed by GitHub
parent e82649139b
commit 2d039d3c6b
148 changed files with 4073 additions and 870 deletions

View File

@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk;
import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -15,6 +16,14 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
/**
* The entry point of the Mapbox Android SDK.
* <p>
* Obtain a reference by calling {@link #getInstance(Context, String)}. Usually this class is configured in
* {@link Application#onCreate()} and is responsible for the active access token, application context, and
* connectivity state.
* </p>
*/
public final class Mapbox {
private static Mapbox INSTANCE;
@@ -25,7 +34,7 @@ public final class Mapbox {
/**
* Get an instance of Mapbox.
* <p>
* This class manages the active access token, application context and connectivity state.
* This class manages the active access token, application context, and connectivity state.
* </p>
*
* @param context Android context which holds or is an application context
@@ -52,9 +61,9 @@ public final class Mapbox {
}
/**
* Access Token for this application.
* Access token for this application.
*
* @return Mapbox Access Token
* @return Mapbox access token
*/
public static String getAccessToken() {
validateMapbox();
@@ -72,7 +81,7 @@ public final class Mapbox {
}
/**
* Runtime validation of Access Token.
* Runtime validation of access token.
*
* @throws MapboxConfigurationException exception thrown when not using a valid accessToken
*/
@@ -92,11 +101,11 @@ public final class Mapbox {
}
/**
* Manually sets the connectivity state of the app. This is useful for apps that control their
* Manually sets the connectivity state of the app. This is useful for apps which control their
* own connectivity state and want to bypass any checks to the ConnectivityManager.
*
* @param connected flag to determine the connectivity state, true for connected, false for
* disconnected, null for ConnectivityManager to determine.
* disconnected, and null for ConnectivityManager to determine.
*/
public static synchronized void setConnected(Boolean connected) {
// Connectivity state overridden by app
@@ -104,10 +113,10 @@ public final class Mapbox {
}
/**
* Determines whether we have an Internet connection available. Please do not rely on this
* method in your apps, this method is used internally by the SDK.
* Determines whether we have an internet connection available. Please do not rely on this
* method in your apps. This method is used internally by the SDK.
*
* @return true if there is an Internet connection, false otherwise
* @return true if there is an internet connection, false otherwise
*/
public static synchronized Boolean isConnected() {
if (INSTANCE.connected != null) {
@@ -119,4 +128,4 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
}
}

View File

@@ -1,15 +1,18 @@
package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
import com.mapbox.mapboxsdk.maps.MapView;
import java.nio.ByteBuffer;
/**
* Icon is the visual representation of a {@link Marker} on a {@link MapView}.
* Icon is the visual representation of a Marker on a MapView.
*
* @see Marker
* @see IconFactory
*/
public class Icon {
private Bitmap mBitmap;
private String mId;
@@ -19,29 +22,67 @@ public class Icon {
}
/**
* {@link String} identifier for this {@link Icon}.
* String identifier for this icon.
*
* @return {@link String} identifier for this {@link Icon}.
* @return String identifier for this icon.
*/
public String getId() {
return mId;
}
/**
* Get the {@link Bitmap} being used for this {@link Icon}.
* Get the bitmap being used for this icon.
*
* @return The {@link Bitmap} being used for the {@link Icon}.
* @return The bitmap being used for the icon.
*/
public Bitmap getBitmap() {
if (mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false);
}
return mBitmap;
}
/**
* Compares this {@link Icon} object with another {@link Icon} and determines if they match.
* Get the icon bitmap scale.
* <p>
* Requires the bitmap to be set before calling this method.
* </p>
*
* @param object Another {@link Icon} to compare with this object.
* @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else,
* false.
* @return the scale of the bitmap
*/
public float getScale() {
if (mBitmap == null) {
throw new IllegalStateException("Required to set a Icon before calling getScale");
}
float density = mBitmap.getDensity();
if (density == Bitmap.DENSITY_NONE) {
density = DisplayMetrics.DENSITY_DEFAULT;
}
return density / DisplayMetrics.DENSITY_DEFAULT;
}
/**
* Get the icon bitmap bytes.
* <p>
* Requires the bitmap to be set before calling this method.
* </p>
*
* @return the bytes of the bitmap
*/
public byte[] toBytes() {
if (mBitmap == null) {
throw new IllegalStateException("Required to set a Icon before calling toBytes");
}
ByteBuffer buffer = ByteBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight());
mBitmap.copyPixelsToBuffer(buffer);
return buffer.array();
}
/**
* Compares this icon object with another icon and determines if they match.
*
* @param object Another iconi to compare with this object.
* @return True if the icon being passed in matches this icon object. Else, false.
*/
@Override
public boolean equals(Object object) {
@@ -53,11 +94,7 @@ public class Icon {
}
Icon icon = (Icon) object;
if (!mBitmap.equals(icon.mBitmap)) {
return false;
}
return mId.equals(icon.mId);
return mBitmap.equals(icon.mBitmap) && mId.equals(icon.mId);
}
/**

View File

@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -361,6 +362,9 @@ public class MarkerView extends Marker {
*/
@Override
public Icon getIcon() {
if (markerViewIcon == null) {
setIcon(IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarkerView());
}
return markerViewIcon;
}

View File

@@ -156,7 +156,7 @@ public final class CameraPosition implements Parcelable {
}
/**
* Builder for composing {@link CameraPosition} objects.
* Builder for composing CameraPosition objects.
*/
public static final class Builder {
@@ -190,7 +190,7 @@ public final class CameraPosition implements Parcelable {
/**
* Create Builder with an existing CameraPosition data.
*
* @param typedArray TypedArray containgin attribute values
* @param typedArray TypedArray containing attribute values
*/
public Builder(TypedArray typedArray) {
super();

View File

@@ -15,7 +15,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Factory for creating {@link CameraUpdate} objects.
* Factory for creating CameraUpdate objects.
*/
public final class CameraUpdateFactory {

View File

@@ -16,7 +16,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyBearingTracking {
/**
* Indicates the parameter accepts one of the values from {@link MyBearingTracking}.
* Indicates that the parameter accepts one of the values from MyBearingTracking.
*/
@IntDef( {NONE, COMPASS, GPS, /**COMBINED**/})
@Retention(RetentionPolicy.SOURCE)
@@ -38,6 +38,4 @@ public class MyBearingTracking {
*/
public static final int GPS = 0x00000008;
// public static final int COMBINED = 0x00000012;
}

View File

@@ -17,7 +17,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyLocationTracking {
/**
* Indicates the parameter accepts one of the values from {@link MyLocationTracking}.
* Indicates the parameter accepts one of the values from MyLocationTracking.
*/
@IntDef( {TRACKING_NONE, TRACKING_FOLLOW})
@Retention(RetentionPolicy.SOURCE)
@@ -30,7 +30,7 @@ public class MyLocationTracking {
public static final int TRACKING_NONE = 0x00000000;
/**
* Tracking the location of the user, {@link MapView} will reposition to center of {@link MyLocationView}
* Tracking the location of the user. {@link MapView} will reposition to center of {@link MyLocationView}
*/
public static final int TRACKING_FOLLOW = 0x00000004;

View File

@@ -19,7 +19,7 @@ public class Style {
/**
* Indicates the parameter accepts one of the values from {@link Style}. Using one of these
* Indicates the parameter accepts one of the values from Style. Using one of these
* constants means your map style will always use the latest version and may change as we
* improve the style
*/

View File

@@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location;
import android.content.Context;
import android.location.Location;
import android.util.Log;
import android.support.annotation.NonNull;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
@@ -15,6 +15,8 @@ import com.mapzen.android.lost.api.LostApiClient;
import java.lang.ref.WeakReference;
import timber.log.Timber;
/**
* Manages locational updates. Contains methods to register and unregister location listeners.
* <ul>
@@ -33,8 +35,6 @@ import java.lang.ref.WeakReference;
public class LocationSource extends LocationEngine implements
LostApiClient.ConnectionCallbacks, LocationListener {
private static final String LOG_TAG = LocationSource.class.getSimpleName();
private static LocationEngine instance;
private WeakReference<Context> context;
@@ -48,7 +48,13 @@ public class LocationSource extends LocationEngine implements
.build();
}
public static synchronized LocationEngine getLocationEngine(Context context) {
/**
* Get the LocationEngine instance.
*
* @param context a Context from which the application context is derived
* @return the LocationEngine instance
*/
public static synchronized LocationEngine getLocationEngine(@NonNull Context context) {
if (instance == null) {
instance = new LocationSource(context.getApplicationContext());
}
@@ -56,6 +62,10 @@ public class LocationSource extends LocationEngine implements
return instance;
}
/**
* Activate the location engine which will connect whichever location provider you are using. You'll need to call
* this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}.
*/
@Override
public void activate() {
if (lostApiClient != null && !lostApiClient.isConnected()) {
@@ -63,6 +73,11 @@ public class LocationSource extends LocationEngine implements
}
}
/**
* Disconnect the location engine which is useful when you no longer need location updates or requesting the users
* {@link LocationEngine#getLastLocation()}. Before deactivating, you'll need to stop request user location updates
* using {@link LocationEngine#removeLocationUpdates()}.
*/
@Override
public void deactivate() {
if (lostApiClient != null && lostApiClient.isConnected()) {
@@ -70,11 +85,20 @@ public class LocationSource extends LocationEngine implements
}
}
/**
* Check if your location provider has been activated/connected. This is mainly used internally but is also useful in
* the rare case when you'd like to know if your location engine is connected or not.
*
* @return boolean true if the location engine has been activated/connected, else false.
*/
@Override
public boolean isConnected() {
return lostApiClient.isConnected();
}
/**
* Invoked when the location provider has connected.
*/
@Override
public void onConnected() {
for (LocationEngineListener listener : locationListeners) {
@@ -82,11 +106,19 @@ public class LocationSource extends LocationEngine implements
}
}
/**
* Invoked when the location provider connection has been suspended.
*/
@Override
public void onConnectionSuspended() {
Log.d(LOG_TAG, "Connection suspended.");
Timber.d("Connection suspended.");
}
/**
* Returns the Last known location is the location provider is connected and location permissions are granted.
*
* @return the last known location
*/
@Override
public Location getLastLocation() {
if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
@@ -97,6 +129,9 @@ public class LocationSource extends LocationEngine implements
return null;
}
/**
* Request location updates to the location provider.
*/
@Override
public void requestLocationUpdates() {
// Common params
@@ -122,6 +157,9 @@ public class LocationSource extends LocationEngine implements
}
}
/**
* Dismiss ongoing location update to the location provider.
*/
@Override
public void removeLocationUpdates() {
if (lostApiClient.isConnected()) {
@@ -129,20 +167,15 @@ public class LocationSource extends LocationEngine implements
}
}
/**
* Invoked when the Location has changed.
*
* @param location the new location
*/
@Override
public void onLocationChanged(Location location) {
for (LocationEngineListener listener : locationListeners) {
listener.onLocationChanged(location);
}
}
@Override
public void onProviderDisabled(String provider) {
Log.d(LOG_TAG, "Provider disabled: " + provider);
}
@Override
public void onProviderEnabled(String provider) {
Log.d(LOG_TAG, "Provider enabled: " + provider);
}
}

View File

@@ -100,6 +100,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (selectedMarkers.contains(marker)) {
selectedMarkers.remove(marker);
}
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -112,6 +116,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (selectedMarkers.contains(marker)) {
selectedMarkers.remove(marker);
}
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -124,6 +132,7 @@ class AnnotationManager {
Annotation annotation;
int count = annotationsArray.size();
long[] ids = new long[count];
selectedMarkers.clear();
for (int i = 0; i < count; i++) {
ids[i] = annotationsArray.keyAt(i);
annotation = annotationsArray.get(ids[i]);
@@ -383,12 +392,15 @@ class AnnotationManager {
for (Marker nearbyMarker : nearbyMarkers) {
for (Marker selectedMarker : selectedMarkers) {
if (nearbyMarker.equals(selectedMarker)) {
if (onMarkerClickListener != null) {
// end developer has provided a custom click listener
if (nearbyMarker instanceof MarkerView) {
handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) nearbyMarker);
} else if (onMarkerClickListener != null) {
handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
if (!handledDefaultClick) {
deselectMarker(nearbyMarker);
}
}
if (!handledDefaultClick) {
// only deselect marker if user didn't handle the click event themselves
deselectMarker(nearbyMarker);
}
return true;
}

View File

@@ -0,0 +1,67 @@
package com.mapbox.mapboxsdk.maps;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
private boolean idle = true;
private OnCameraMoveStartedListener onCameraMoveStartedListener;
private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
private OnCameraMoveListener onCameraMoveListener;
private OnCameraIdleListener onCameraIdleListener;
void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
this.onCameraMoveStartedListener = onCameraMoveStartedListener;
}
void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
}
void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
this.onCameraMoveListener = onCameraMoveListener;
}
void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
this.onCameraIdleListener = onCameraIdleListener;
}
@Override
public void onCameraMoveStarted(int reason) {
if (!idle) {
return;
}
idle = false;
if (onCameraMoveStartedListener != null) {
onCameraMoveStartedListener.onCameraMoveStarted(reason);
}
}
@Override
public void onCameraMove() {
if (onCameraMoveListener != null && !idle) {
onCameraMoveListener.onCameraMove();
}
}
@Override
public void onCameraMoveCanceled() {
if (onCameraMoveCanceledListener != null && !idle) {
onCameraMoveCanceledListener.onCameraMoveCanceled();
}
}
@Override
public void onCameraIdle() {
if (onCameraIdleListener != null && !idle) {
idle = true;
onCameraIdleListener.onCameraIdle();
}
}
}

View File

@@ -2,6 +2,9 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
/**
* Interface definition of a callback that is invoked when the focal point will change.
*/
public interface FocalPointChangeListener {
void onFocalPointChanged(PointF pointF);

View File

@@ -1,15 +1,14 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -41,113 +40,28 @@ class IconManager {
Icon loadIconForMarker(Marker marker) {
Icon icon = marker.getIcon();
// calculating average before adding
int iconSize = icons.size() + 1;
// TODO replace former if case with anchor implementation,
// current workaround for having extra pixels is diving height by 2
if (icon == null) {
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
marker.setIcon(icon);
// TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2
// TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
icon = loadDefaultIconForMarker(marker);
} else {
Bitmap bitmap = icon.getBitmap();
averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
}
if (!icons.contains(icon)) {
icons.add(icon);
loadIcon(icon);
} else {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
updateAverageIconSize(icon);
}
addIcon(icon);
return icon;
}
Icon loadIconForMarkerView(MarkerView marker) {
void loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
int iconSize = icons.size() + 1;
if (icon == null) {
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView();
marker.setIcon(icon);
}
Bitmap bitmap = icon.getBitmap();
averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
if (!icons.contains(icon)) {
icons.add(icon);
} else {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
}
return icon;
updateAverageIconSize(bitmap);
addIcon(icon, false);
}
int getTopOffsetPixelsForIcon(Icon icon) {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
void loadIcon(Icon icon) {
Bitmap bitmap = icon.getBitmap();
String id = icon.getId();
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
}
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
bitmap.copyPixelsToBuffer(buffer);
float density = bitmap.getDensity();
if (density == Bitmap.DENSITY_NONE) {
density = DisplayMetrics.DENSITY_DEFAULT;
}
float scale = density / DisplayMetrics.DENSITY_DEFAULT;
nativeMapView.addAnnotationIcon(
id,
bitmap.getWidth(),
bitmap.getHeight(),
scale, buffer.array());
}
void reloadIcons() {
int count = icons.size();
for (int i = 0; i < count; i++) {
Icon icon = icons.get(i);
loadIcon(icon);
}
}
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
marker.setIcon(icon);
}
if (!icons.contains(icon)) {
icons.add(icon);
loadIcon(icon);
} else {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
}
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
int getAverageIconHeight() {
return averageIconHeight;
}
@@ -155,4 +69,80 @@ class IconManager {
int getAverageIconWidth() {
return averageIconWidth;
}
private Icon loadDefaultIconForMarker(Marker marker) {
Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
marker.setIcon(icon);
return icon;
}
private void addIcon(Icon icon) {
addIcon(icon, true);
}
private void addIcon(Icon icon, boolean addIconToMap) {
if (!icons.contains(icon)) {
icons.add(icon);
if (addIconToMap) {
loadIcon(icon);
}
} else {
validateIconChanged(icon);
}
}
private void updateAverageIconSize(Icon icon) {
updateAverageIconSize(icon.getBitmap());
}
private void updateAverageIconSize(Bitmap bitmap) {
updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
}
private void updateAverageIconSize(int width, int height) {
int iconSize = icons.size() + 1;
averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
}
private void loadIcon(Icon icon) {
Bitmap bitmap = icon.getBitmap();
nativeMapView.addAnnotationIcon(icon.getId(),
bitmap.getWidth(),
bitmap.getHeight(),
icon.getScale(),
icon.toBytes());
}
void reloadIcons() {
for (Icon icon : icons) {
loadIcon(icon);
}
}
private void validateIconChanged(Icon icon) {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
}
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
icon = loadDefaultIconForMarker(marker);
}
addIcon(icon);
setTopOffsetPixels(marker, mapboxMap, icon);
}
private void setTopOffsetPixels(Marker marker, MapboxMap mapboxMap, Icon icon) {
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
}

View File

@@ -22,6 +22,8 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.utils.MathUtils;
import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
/**
* Manages gestures events on a MapView.
* <p>
@@ -35,6 +37,7 @@ final class MapGestureDetector {
private final UiSettings uiSettings;
private final TrackingSettings trackingSettings;
private final AnnotationManager annotationManager;
private final CameraChangeDispatcher cameraChangeDispatcher;
private final GestureDetectorCompat gestureDetector;
private final ScaleGestureDetector scaleGestureDetector;
@@ -56,12 +59,14 @@ final class MapGestureDetector {
private boolean scaleGestureOccurred = false;
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
TrackingSettings trackingSettings, AnnotationManager annotationManager) {
TrackingSettings trackingSettings, AnnotationManager annotationManager,
CameraChangeDispatcher cameraChangeDispatcher) {
this.annotationManager = annotationManager;
this.transform = transform;
this.projection = projection;
this.uiSettings = uiSettings;
this.trackingSettings = trackingSettings;
this.cameraChangeDispatcher = cameraChangeDispatcher;
// Touch gesture detectors
gestureDetector = new GestureDetectorCompat(context, new GestureListener());
@@ -187,6 +192,7 @@ final class MapGestureDetector {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
getLocationFromGesture(event.getX(), event.getY()), transform));
scrollInProgress = false;
cameraChangeDispatcher.onCameraIdle();
}
twoTap = false;
@@ -273,6 +279,9 @@ final class MapGestureDetector {
break;
}
// notify camera change listener
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
// Single finger double tap
if (focalPoint != null) {
// User provided focal point
@@ -337,6 +346,7 @@ final class MapGestureDetector {
// and ignore when a scale gesture has occurred
return false;
}
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
float screenDensity = uiSettings.getPixelRatio();
@@ -362,9 +372,7 @@ final class MapGestureDetector {
long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE);
// update transformation
transform.setGestureInProgress(true);
transform.moveBy(offsetX, offsetY, animationTime);
transform.setGestureInProgress(false);
if (onFlingListener != null) {
onFlingListener.onFling();
@@ -375,12 +383,6 @@ final class MapGestureDetector {
// Called for drags
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!scrollInProgress) {
scrollInProgress = true;
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(e1.getX(), e1.getY()),
MapboxEvent.GESTURE_PAN_START, transform));
}
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
}
@@ -389,10 +391,19 @@ final class MapGestureDetector {
return false;
}
if (!scrollInProgress) {
scrollInProgress = true;
// Cancel any animation
transform.cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(e1.getX(), e1.getY()),
MapboxEvent.GESTURE_PAN_START, transform));
}
// reset tracking if needed
trackingSettings.resetTrackingModesIfRequired(true, false, false);
// Cancel any animation
transform.cancelTransitions();
// Scroll the map
transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/);
@@ -446,6 +457,8 @@ final class MapGestureDetector {
// If scale is large enough ignore a tap
scaleFactor *= detector.getScaleFactor();
if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
// notify camera change listener
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
zoomStarted = true;
}
@@ -465,9 +478,6 @@ final class MapGestureDetector {
return false;
}
// Cancel any animation
transform.cancelTransitions();
// Gesture is a quickzoom if there aren't two fingers
quickZoom = !twoTap;
@@ -512,6 +522,9 @@ final class MapGestureDetector {
return false;
}
// notify camera change listener
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -522,6 +535,7 @@ final class MapGestureDetector {
// Called when the fingers leave the screen
@Override
public void onRotateEnd(RotateGestureDetector detector) {
// notify camera change listener
beginTime = 0;
totalAngle = 0.0f;
started = false;
@@ -553,13 +567,8 @@ final class MapGestureDetector {
if (!started) {
return false;
}
// Cancel any animation
transform.cancelTransitions();
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
trackingSettings.resetTrackingModesIfRequired(true, true, false);
// Get rotate value
@@ -593,6 +602,8 @@ final class MapGestureDetector {
return false;
}
// notify camera change listener
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -633,9 +644,6 @@ final class MapGestureDetector {
return false;
}
// Cancel any animation
transform.cancelTransitions();
// Get tilt value (scale and clamp)
double pitch = transform.getTilt();
pitch -= 0.1 * detector.getShovePixelsDelta();

View File

@@ -131,6 +131,9 @@ public class MapView extends FrameLayout {
// callback for zooming in the camera
CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
// callback for camera change events
CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
@@ -145,13 +148,14 @@ public class MapView extends FrameLayout {
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
markerViewManager, iconManager, annotations, markers, polygons, polylines);
Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings);
Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
cameraChangeDispatcher);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
registerTouchListener, annotationManager);
registerTouchListener, annotationManager, cameraChangeDispatcher);
// user input
mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
annotationManager);
annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);

View File

@@ -41,6 +41,7 @@ import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
@@ -69,6 +70,7 @@ public final class MapboxMap {
private final Transform transform;
private final AnnotationManager annotationManager;
private final MyLocationViewSettings myLocationViewSettings;
private final CameraChangeDispatcher cameraChangeDispatcher;
private final OnRegisterTouchListener onRegisterTouchListener;
@@ -76,7 +78,7 @@ public final class MapboxMap {
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
AnnotationManager annotations) {
AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) {
this.nativeMapView = map;
this.uiSettings = ui;
this.trackingSettings = tracking;
@@ -85,6 +87,7 @@ public final class MapboxMap {
this.annotationManager = annotations.bind(this);
this.transform = transform;
this.onRegisterTouchListener = listener;
this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) {
@@ -565,6 +568,20 @@ public final class MapboxMap {
return projection;
}
//
//
//
/**
* Get the global light source used to change lighting conditions on extruded fill layers.
*
* @return the global light source
*/
@Nullable
public Light getLight() {
return nativeMapView.getLight();
}
//
// Camera API
//
@@ -1623,10 +1640,51 @@ public final class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
@Deprecated
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
transform.setOnCameraChangeListener(listener);
}
/**
* Sets a callback that is invoked when camera movement has ended.
*
* @param listener the listener to notify
*/
@UiThread
public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
cameraChangeDispatcher.setOnCameraIdleListener(listener);
}
/**
* Sets a callback that is invoked when camera movement was cancelled.
*
* @param listener the listener to notify
*/
@UiThread
public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
}
/**
* Sets a callback that is invoked when camera movement has started.
*
* @param listener the listener to notify
*/
@UiThread
public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) {
cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
}
/**
* Sets a callback that is invoked when camera position changes.
*
* @param listener the listener to notify
*/
@UiThread
public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
cameraChangeDispatcher.setOnCameraMoveListener(listener);
}
/**
* Sets a callback that's invoked on every frame rendered to the map view.
*
@@ -1941,7 +1999,12 @@ public final class MapboxMap {
/**
* Interface definition for a callback to be invoked when the camera changes position.
*
* @deprecated Replaced by {@link MapboxMap.OnCameraMoveStartedListener}, {@link MapboxMap.OnCameraMoveListener} and
* {@link MapboxMap.OnCameraIdleListener}. The order in which the deprecated onCameraChange method will be called in
* relation to the methods in the new camera change listeners is undefined.
*/
@Deprecated
public interface OnCameraChangeListener {
/**
* Called after the camera position has changed. During an animation,
@@ -1953,6 +2016,56 @@ public final class MapboxMap {
void onCameraChange(CameraPosition position);
}
/**
* Interface definition for a callback to be invoked for when the camera motion starts.
*/
public interface OnCameraMoveStartedListener {
int REASON_API_GESTURE = 1;
int REASON_DEVELOPER_ANIMATION = 2;
int REASON_API_ANIMATION = 3;
/**
* Called when the camera starts moving after it has been idle or when the reason for camera motion has changed.
*
* @param reason the reason for the camera change
*/
void onCameraMoveStarted(int reason);
}
/**
* Interface definition for a callback to be invoked for when the camera changes position.
*/
public interface OnCameraMoveListener {
/**
* Called repeatedly as the camera continues to move after an onCameraMoveStarted call.
* This may be called as often as once every frame and should not perform expensive operations.
*/
void onCameraMove();
}
/**
* Interface definition for a callback to be invoked for when the camera's motion has been stopped or when the camera
* starts moving for a new reason.
*/
public interface OnCameraMoveCanceledListener {
/**
* Called when the developer explicitly calls the cancelTransitions() method or if the reason for camera motion has
* changed before the onCameraIdle had a chance to fire after the previous animation.
* Do not update or animate the camera from within this method.
*/
void onCameraMoveCanceled();
}
/**
* Interface definition for a callback to be invoked for when camera movement has ended.
*/
public interface OnCameraIdleListener {
/**
* Called when camera movement has ended.
*/
void onCameraIdle();
}
/**
* Interface definition for a callback to be invoked when a frame is rendered to the map view.
*

View File

@@ -36,7 +36,7 @@ import java.util.Arrays;
public class MapboxMapOptions implements Parcelable {
private static final float FOUR_DP = 4f;
private static final float EIGHTY_NINE_DP = 92f;
private static final float NINETY_TWO_DP = 92f;
private CameraPosition cameraPosition;
@@ -241,7 +241,7 @@ public class MapboxMapOptions implements Parcelable {
R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft,
EIGHTY_NINE_DP * pxlRatio)),
NINETY_TWO_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop,
FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight,

View File

@@ -27,6 +27,7 @@ import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -617,7 +618,7 @@ final class NativeMapView {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
@@ -882,12 +883,15 @@ final class NativeMapView {
fileSource.setApiBaseUrl(baseUrl);
}
public float getPixelRatio() {
return pixelRatio;
public Light getLight() {
if (isDestroyedOn("getLight")) {
return null;
}
return nativeGetLight();
}
public Context getContext() {
return mapView.getContext();
public float getPixelRatio() {
return pixelRatio;
}
//
@@ -1117,6 +1121,8 @@ final class NativeMapView {
String[] layerIds,
Object[] filter);
private native Light nativeGetLight();
int getWidth() {
if (isDestroyedOn("")) {
return 0;

View File

@@ -282,8 +282,10 @@ public final class TrackingSettings {
*/
void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition,
boolean isFromLocation) {
resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
isFromLocation);
if (currentCameraPosition.target != null) {
resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
isFromLocation);
}
}
Location getMyLocation() {

View File

@@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
/**
* Resembles the current Map transformation.
@@ -33,13 +34,18 @@ final class Transform implements MapView.OnMapChangedListener {
private CameraPosition cameraPosition;
private MapboxMap.CancelableCallback cameraCancelableCallback;
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings) {
private CameraChangeDispatcher cameraChangeDispatcher;
Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings,
CameraChangeDispatcher cameraChangeDispatcher) {
this.mapView = mapView;
this.markerViewManager = markerViewManager;
this.trackingSettings = trackingSettings;
this.myLocationView = trackingSettings.getMyLocationView();
this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull MapboxMap mapboxMap, @NonNull MapboxMapOptions options) {
@@ -79,6 +85,7 @@ final class Transform implements MapView.OnMapChangedListener {
cameraCancelableCallback.onFinish();
cameraCancelableCallback = null;
}
cameraChangeDispatcher.onCameraIdle();
mapView.removeOnMapChangedListener(this);
}
}
@@ -89,10 +96,12 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
if (callback != null) {
callback.onFinish();
}
cameraChangeDispatcher.onCameraIdle();
}
}
@@ -103,6 +112,8 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -118,8 +129,9 @@ final class Transform implements MapView.OnMapChangedListener {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -134,7 +146,12 @@ final class Transform implements MapView.OnMapChangedListener {
@Nullable
CameraPosition invalidateCameraPosition() {
if (mapView != null) {
cameraPosition = mapView.getCameraPosition();
CameraPosition cameraPosition = mapView.getCameraPosition();
if (this.cameraPosition != null && !this.cameraPosition.equals(cameraPosition)) {
cameraChangeDispatcher.onCameraMove();
}
this.cameraPosition = cameraPosition;
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
}
@@ -143,10 +160,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void cancelTransitions() {
// notify user about cancel
cameraChangeDispatcher.onCameraMoveCanceled();
// notify animateCamera and easeCamera about cancelling
if (cameraCancelableCallback != null) {
cameraChangeDispatcher.onCameraIdle();
cameraCancelableCallback.onCancel();
cameraCancelableCallback = null;
}
// cancel ongoing transitions
mapView.cancelTransitions();
}
@@ -156,6 +180,10 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.resetNorth();
}
//
// Camera change listener API
//
void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) {
this.onCameraChangeListener = listener;
}
@@ -171,9 +199,6 @@ final class Transform implements MapView.OnMapChangedListener {
}
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
// Cancel any animation
cancelTransitions();
CameraPosition cameraPosition = invalidateCameraPosition();
if (cameraPosition != null) {
int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1));
@@ -186,6 +211,15 @@ final class Transform implements MapView.OnMapChangedListener {
}
void setZoom(double zoom, @NonNull PointF focalPoint, long duration) {
mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(int change) {
if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
mapView.removeOnMapChangedListener(this);
cameraChangeDispatcher.onCameraIdle();
}
}
});
mapView.setZoom(zoom, focalPoint, duration);
}
@@ -277,6 +311,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void moveBy(double offsetX, double offsetY, long duration) {
if (duration > 0) {
mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(int change) {
if (change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
mapView.removeOnMapChangedListener(this);
cameraChangeDispatcher.onCameraIdle();
}
}
});
}
mapView.moveBy(offsetX, offsetY, duration);
}

View File

@@ -193,12 +193,16 @@ public final class UiSettings {
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
setLogoEnabled(options.getLogoEnabled());
setLogoGravity(options.getLogoGravity());
int[] logoMargins = options.getLogoMargins();
setLogoMargins(resources, options.getLogoMargins());
}
private void setLogoMargins(Resources resources, int[] logoMargins) {
if (logoMargins != null) {
setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
} else {
int twoDp = (int) resources.getDimension(R.dimen.mapbox_two_dp);
setLogoMargins(twoDp, twoDp, twoDp, twoDp);
// user did not specify margins when programmatically creating a map
int fourDp = (int) resources.getDimension(R.dimen.mapbox_four_dp);
setLogoMargins(fourDp, fourDp, fourDp, fourDp);
}
}
@@ -223,17 +227,25 @@ public final class UiSettings {
private void initialiseAttribution(Context context, MapboxMapOptions options) {
setAttributionEnabled(options.getAttributionEnabled());
setAttributionGravity(options.getAttributionGravity());
int[] attributionMargins = options.getAttributionMargins();
if (attributionMargins != null) {
setAttributionMargins(attributionMargins[0], attributionMargins[1],
attributionMargins[2], attributionMargins[3]);
}
setAttributionMargins(context, options.getAttributionMargins());
int attributionTintColor = options.getAttributionTintColor();
setAttributionTintColor(attributionTintColor != -1
? attributionTintColor : ColorUtils.getPrimaryColor(context));
}
private void setAttributionMargins(Context context, int[] attributionMargins) {
if (attributionMargins != null) {
setAttributionMargins(attributionMargins[0], attributionMargins[1],
attributionMargins[2], attributionMargins[3]);
} else {
// user did not specify margins when programmatically creating a map
Resources resources = context.getResources();
int margin = (int) resources.getDimension(R.dimen.mapbox_four_dp);
int leftMargin = (int) resources.getDimension(R.dimen.mapbox_ninety_two_dp);
setAttributionMargins(leftMargin, margin, margin, margin);
}
}
private void saveAttribution(Bundle outState) {
outState.putInt(MapboxConstants.STATE_ATTRIBUTION_GRAVITY, getAttributionGravity());
outState.putInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT, getAttributionMarginLeft());

View File

@@ -440,6 +440,7 @@ public class MyLocationView extends View {
} else {
// Disable location and user dot
location = null;
locationSource.removeLocationUpdates();
locationSource.removeLocationEngineListener(userLocationListener);
locationSource.deactivate();
}

View File

@@ -47,7 +47,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing a list of all
* {@link OfflineRegion} in the database, or an error message otherwise.
* OfflineRegion in the database or an error message otherwise.
*/
public interface ListOfflineRegionsCallback {
/**
@@ -67,7 +67,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing the newly created
* {@link OfflineRegion} in the database, or an error message otherwise.
* OfflineRegion in the database or an error message otherwise.
*/
public interface CreateOfflineRegionCallback {
/**

View File

@@ -4,6 +4,7 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.storage.FileSource;
@@ -37,6 +38,9 @@ public class OfflineRegion {
//Region id
private long id;
// delete status
private boolean isDeleted;
private OfflineRegionDefinition definition;
/**
@@ -95,7 +99,7 @@ public class OfflineRegion {
}
/**
* This callback receives an asynchronous response containing the {@link OfflineRegionStatus}
* This callback receives an asynchronous response containing the OfflineRegionStatus
* of the offline region, or a {@link String} error message otherwise.
*/
public interface OfflineRegionStatusCallback {
@@ -248,7 +252,7 @@ public class OfflineRegion {
*
* @param observer the observer to be notified
*/
public void setObserver(@NonNull final OfflineRegionObserver observer) {
public void setObserver(@Nullable final OfflineRegionObserver observer) {
setOfflineRegionObserver(new OfflineRegionObserver() {
@Override
public void onStatusChanged(final OfflineRegionStatus status) {
@@ -256,7 +260,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
observer.onStatusChanged(status);
if (observer != null) {
observer.onStatusChanged(status);
}
}
});
}
@@ -268,7 +274,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
observer.onError(error);
if (observer != null) {
observer.onError(error);
}
}
});
}
@@ -280,7 +288,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
observer.mapboxTileCountLimitExceeded(limit);
if (observer != null) {
observer.mapboxTileCountLimitExceeded(limit);
}
}
});
}
@@ -347,28 +357,31 @@ public class OfflineRegion {
* @param callback the callback to be invoked
*/
public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
deleteOfflineRegion(new OfflineRegionDeleteCallback() {
@Override
public void onDelete() {
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onDelete();
OfflineRegion.this.finalize();
}
});
}
if (!isDeleted) {
deleteOfflineRegion(new OfflineRegionDeleteCallback() {
@Override
public void onDelete() {
isDeleted = true;
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onDelete();
OfflineRegion.this.finalize();
}
});
}
@Override
public void onError(final String error) {
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onError(error);
}
});
}
});
@Override
public void onError(final String error) {
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onError(error);
}
});
}
});
}
}
/**

View File

@@ -5,9 +5,15 @@ import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Resource provides access to resource types.
*/
public final class Resource {
// Note: Keep this in sync with include/mbgl/storage/resource.hpp
/**
* Resource type variants.
*/
@IntDef( {UNKNOWN, STYLE, SOURCE, TILE, GLYPHS, SPRITE_IMAGE, SPRITE_JSON})
@Retention(RetentionPolicy.SOURCE)
public @interface Kind {

View File

@@ -13,7 +13,7 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import java.util.Map;
/**
* Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s.
* Composite functions combine Camera and SourceFunctions.
* <p>
* Composite functions allow the appearance of a map feature to change with both its
* properties and zoom. Each stop is an array with two elements, the first is an object

View File

@@ -11,7 +11,7 @@ import java.util.Collections;
public class Filter {
/**
* Base {@link Filter} statement. Subclassed to provide concrete statements.
* Base Filter statement. Subclassed to provide concrete statements.
*/
public abstract static class Statement {
protected final String operator;

View File

@@ -467,6 +467,27 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface FILL_EXTRUSION_TRANSLATE_ANCHOR {}
// ANCHOR: Whether extruded geometries are lit relative to the map or viewport.
/**
* The position of the light source is aligned to the rotation of the map.
*/
public static final String ANCHOR_MAP = "map";
/**
* The position of the light source is aligned to the rotation of the viewport.
*/
public static final String ANCHOR_VIEWPORT = "viewport";
/**
* Whether extruded geometries are lit relative to the map or viewport.
*/
@StringDef({
ANCHOR_MAP,
ANCHOR_VIEWPORT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ANCHOR {}
private Property() {
}

View File

@@ -1,23 +1,51 @@
package com.mapbox.mapboxsdk.style.layers;
/**
* Resembles transition property from the style specification.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#transition">Transition documentation</a>
*/
public class TransitionOptions {
private long duration;
private long delay;
/**
* Create a transition property based on duration and a delay.
*
* @param duration the duration of the transition
* @param delay the delay to start the transition
*/
public TransitionOptions(long duration, long delay) {
this.duration = duration;
this.delay = delay;
}
/**
* Create a transition property based on duration and a delay.
*
* @param duration the duration of the transition
* @param delay the delay to start the transition
* @return a new transition property object
*/
public static TransitionOptions fromTransitionOptions(long duration, long delay) {
return new TransitionOptions(duration, delay);
}
/**
* Get the transition duration.
*
* @return the transition duration
*/
public long getDuration() {
return duration;
}
/**
* Get the transition delay.
*
* @return the transition delay
*/
public long getDelay() {
return delay;
}

View File

@@ -0,0 +1,181 @@
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
package com.mapbox.mapboxsdk.style.light;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* The global light source.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
*/
@UiThread
public class Light {
private long nativePtr;
/**
* Creates a Light.
*
* @param nativePtr pointer used by core
*/
public Light(long nativePtr) {
this.nativePtr = nativePtr;
}
/**
* Set the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
*
* @param anchor as String
*/
public void setAnchor(@Property.ANCHOR String anchor) {
nativeSetAnchor(anchor);
}
/**
* Get the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
*
* @return anchor as String
*/
@Property.ANCHOR public String getAnchor() {
return nativeGetAnchor();
}
/**
* Set the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
*
* @param position of the light
*/
public void setPosition(@NonNull Position position) {
nativeSetPosition(position);
}
/**
* Get the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
*
* @return position as Position
*/
public Position getPosition() {
return nativeGetPosition();
}
/**
* Get the Position property transition options.
*
* @return transition options for position
*/
public TransitionOptions getPositionTransition() {
return nativeGetPositionTransition();
}
/**
* Set the Position property transition options.
*
* @param options transition options for position
*/
public void setPositionTransition(TransitionOptions options) {
nativeSetPositionTransition(options.getDuration(), options.getDelay());
}
/**
* Set the Color property. Color tint for lighting extruded geometries.
*
* @param color as int
*/
public void setColor(@ColorInt int color) {
nativeSetColor(PropertyFactory.colorToRgbaString(color));
}
/**
* Set the Color property. Color tint for lighting extruded geometries.
*
* @param color as String
*/
public void setColor(String color) {
nativeSetColor(color);
}
/**
* Get the Color property. Color tint for lighting extruded geometries.
*
* @return color as String
*/
public String getColor() {
return nativeGetColor();
}
/**
* Get the Color property transition options.
*
* @return transition options for color
*/
public TransitionOptions getColorTransition() {
return nativeGetColorTransition();
}
/**
* Set the Color property transition options.
*
* @param options transition options for color
*/
public void setColorTransition(TransitionOptions options) {
nativeSetColorTransition(options.getDuration(), options.getDelay());
}
/**
* Set the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
*
* @param intensity as Float
*/
public void setIntensity(float intensity) {
nativeSetIntensity(intensity);
}
/**
* Get the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
*
* @return intensity as Float
*/
public float getIntensity() {
return nativeGetIntensity();
}
/**
* Get the Intensity property transition options.
*
* @return transition options for intensity
*/
public TransitionOptions getIntensityTransition() {
return nativeGetIntensityTransition();
}
/**
* Set the Intensity property transition options.
*
* @param options transition options for intensity
*/
public void setIntensityTransition(TransitionOptions options) {
nativeSetIntensityTransition(options.getDuration(), options.getDelay());
}
private native void nativeSetAnchor(String anchor);
private native String nativeGetAnchor();
private native void nativeSetPosition(Position position);
private native Position nativeGetPosition();
private native TransitionOptions nativeGetPositionTransition();
private native void nativeSetPositionTransition(long duration, long delay);
private native void nativeSetColor(String color);
private native String nativeGetColor();
private native TransitionOptions nativeGetColorTransition();
private native void nativeSetColorTransition(long duration, long delay);
private native void nativeSetIntensity(float intensity);
private native float nativeGetIntensity();
private native TransitionOptions nativeGetIntensityTransition();
private native void nativeSetIntensityTransition(long duration, long delay);
}

View File

@@ -0,0 +1,81 @@
package com.mapbox.mapboxsdk.style.light;
/**
* Position of the light source relative to lit (extruded) geometries.
* <p>
* The position is constructed out of a radial coordinate, an azimuthal angle and a polar angle.
* where the radial coordinate indicates the distance from the center of the base of an object to its light, the
* azimuthal angle indicates the position of the light relative to 0° (0° when
* {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to viewport corresponds to the top of the
* viewport, or 0° when {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to map corresponds to due
* north, and degrees proceed clockwise), and polar indicates the height of the light
* (from 0°, directly above, to 180°, directly below).
*/
public class Position {
private float radialCoordinate;
private float azimuthalAngle;
private float polarAngle;
/**
* Creates a Position from a radial coordinate, an azimuthal angle & a polar angle.
*
* @param radialCoordinate the distance from the center of the base of an object to its light
* @param azimuthalAngle the position of the light relative to 0°
* @param polarAngle the height of the light
*/
public Position(float radialCoordinate, float azimuthalAngle, float polarAngle) {
this.radialCoordinate = radialCoordinate;
this.azimuthalAngle = azimuthalAngle;
this.polarAngle = polarAngle;
}
/**
* Returns a Position from a radial coordinate, an azimuthal angle & a polar angle
*
* @param radialCoordinate the radial coordinate
* @param azimuthalAngle the azimuthal angle
* @param polarAngle the polar angle
* @return the created Position object
*/
public static Position fromPosition(float radialCoordinate, float azimuthalAngle, float polarAngle) {
return new Position(radialCoordinate, azimuthalAngle, polarAngle);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Position position = (Position) o;
if (Float.compare(position.radialCoordinate, radialCoordinate) != 0) {
return false;
}
if (Float.compare(position.azimuthalAngle, azimuthalAngle) != 0) {
return false;
}
return Float.compare(position.polarAngle, polarAngle) == 0;
}
@Override
public int hashCode() {
int result = (radialCoordinate != +0.0f ? Float.floatToIntBits(radialCoordinate) : 0);
result = 31 * result + (azimuthalAngle != +0.0f ? Float.floatToIntBits(azimuthalAngle) : 0);
result = 31 * result + (polarAngle != +0.0f ? Float.floatToIntBits(polarAngle) : 0);
return result;
}
@Override
public String toString() {
return "Position{"
+ "radialCoordinate=" + radialCoordinate
+ ", azimuthalAngle=" + azimuthalAngle
+ ", polarAngle=" + polarAngle
+ '}';
}
}

View File

@@ -0,0 +1,121 @@
<%
const properties = locals.properties;
const doc = locals.doc;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
package com.mapbox.mapboxsdk.style.light;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* The global light source.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
*/
@UiThread
public class Light {
private long nativePtr;
/**
* Creates a Light.
*
* @param nativePtr pointer used by core
*/
public Light(long nativePtr) {
this.nativePtr = nativePtr;
}
<% for (const property of properties) { -%>
<% if (property.name == "position") {-%>
/**
* Set the <%- camelize(property.name) %> property. <%- property.doc %>
*
* @param position of the light
*/
public void set<%- camelize(property.name) %>(@NonNull Position position) {
nativeSet<%- camelize(property.name) %>(position);
}
/**
* Get the <%- camelize(property.name) %> property. <%- property.doc %>
*
* @return <%- property.name %> as Position
*/
public Position get<%- camelize(property.name) %>() {
return nativeGet<%- camelize(property.name) %>();
}
<% } else { -%>
<% if (property.name == "color") {-%>
/**
* Set the <%- camelize(property.name) %> property. <%- property.doc %>
*
* @param <%- property.name %> as int
*/
public void set<%- camelize(property.name) %>(@ColorInt int <%- property.name %>) {
nativeSet<%- camelize(property.name) %>(PropertyFactory.colorToRgbaString(<%- property.name %>));
}
<% } -%>
/**
* Set the <%- camelize(property.name) %> property. <%- property.doc %>
*
* @param <%- property.name %> as <%- propertyType(property) %>
*/
public void set<%- camelize(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyJavaType(property) %> <%- property.name %>) {
nativeSet<%- camelize(property.name) %>(<%- property.name %>);
}
/**
* Get the <%- camelize(property.name) %> property. <%- property.doc %>
*
* @return <%- property.name %> as <%- propertyType(property) %>
*/
<%- propertyTypeAnnotation(property) %> public <%- propertyJavaType(property) %> get<%- camelize(property.name) %>() {
return nativeGet<%- camelize(property.name) %>();
}
<% } -%>
<% if (property.transition) { -%>
/**
* Get the <%- camelize(property.name) %> property transition options.
*
* @return transition options for <%- property.name %>
*/
public TransitionOptions get<%- camelize(property.name) %>Transition() {
return nativeGet<%- camelize(property.name) %>Transition();
}
/**
* Set the <%- camelize(property.name) %> property transition options.
*
* @param options transition options for <%- property.name %>
*/
public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
}
<% } -%>
<% } -%>
<% for (const property of properties) { -%>
<% if (property.name == "position") {-%>
private native void nativeSet<%- camelize(property.name) %>(Position position);
private native Position nativeGet<%- camelize(property.name) %>();
<% } else { -%>
private native void nativeSet<%- camelize(property.name) %>(<%- propertyJavaType(property) -%> <%- property.name %>);
private native <%- propertyJavaType(property) -%> nativeGet<%- camelize(property.name) %>();
<% } -%>
<% if (property.transition) { -%>
private native TransitionOptions nativeGet<%- camelize(property.name) %>Transition();
private native void nativeSet<%- camelize(property.name) %>Transition(long duration, long delay);
<% } -%>
<% } -%>
}

View File

@@ -0,0 +1,4 @@
/**
* Contains the Mapbox Maps Android Style Light API classes.
*/
package com.mapbox.mapboxsdk.style.light;

View File

@@ -10,13 +10,31 @@ import android.support.annotation.Nullable;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.view.View;
/**
* Animator utility class.
*/
public class AnimatorUtils {
/**
* Animate a view from an animator resource.
*
* @param view the view to be animated
* @param animatorRes the animator resource to be loaded
* @param listener the animator end listener
*/
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes,
@Nullable OnAnimationEndListener listener) {
animate(view, animatorRes, -1, listener);
}
/**
* Animate a view from an animator resource.
*
* @param view the view to be animated
* @param animatorRes the animator resource to be loaded
* @param duration the duration of the animator
* @param listener the animator end listener
*/
public static void animate(final View view, @AnimatorRes int animatorRes, int duration,
@Nullable final OnAnimationEndListener listener) {
if (view == null) {
@@ -43,14 +61,33 @@ public class AnimatorUtils {
animator.start();
}
/**
* Animate a view from an animator resource.
*
* @param view the view to be animated
* @param animatorRes the animator resource to be loaded
*/
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes) {
animate(view, animatorRes, -1);
}
/**
* Animate a view from an animator resource.
*
* @param view the view to be animated
* @param animatorRes the animator resource to be loaded
* @param duration the duration of the animator
*/
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes, int duration) {
animate(view, animatorRes, duration, null);
}
/**
* Animate a view rotation property to a value.
*
* @param view the view to be rotated
* @param rotation the value to animate to
*/
public static void rotate(@NonNull final View view, float rotation) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(view, View.ROTATION, view.getRotation(), rotation);
@@ -64,6 +101,12 @@ public class AnimatorUtils {
rotateAnimator.start();
}
/**
* Animate a view rotation property by a value.
*
* @param view the view to be rotated
* @param rotationBy the value to animate by
*/
public static void rotateBy(@NonNull final View view, float rotationBy) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
view.animate().rotationBy(rotationBy).setInterpolator(new FastOutSlowInInterpolator()).setListener(
@@ -76,6 +119,13 @@ public class AnimatorUtils {
});
}
/**
* Animate a view alpha property to a value.
*
* @param convertView the view to be animated
* @param alpha the value to animate to
* @param listener the animator end listener
*/
public static void alpha(@NonNull final View convertView, float alpha,
@Nullable final OnAnimationEndListener listener) {
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -99,10 +149,19 @@ public class AnimatorUtils {
rotateAnimator.start();
}
/**
* Animate a view alpha property to a value.
*
* @param convertView the view to be animated
* @param alpha the value to animate to
*/
public static void alpha(@NonNull final View convertView, float alpha) {
alpha(convertView, alpha, null);
}
/**
* An interface definition that is invoked when an animation ends.
*/
public interface OnAnimationEndListener {
void onAnimationEnd();
}

View File

@@ -17,6 +17,9 @@ import com.mapbox.mapboxsdk.exceptions.ConversionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Color utility class.
*/
public class ColorUtils {
/**