diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps')
14 files changed, 806 insertions, 554 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java index 05b37bc80d..0c77723354 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -194,7 +194,7 @@ class AnnotationManager { if (ids != null) { id = ids[i]; } else { - //unit test + // unit test id++; } m.setId(id); @@ -359,6 +359,7 @@ class AnnotationManager { return selectedMarkers; } + @NonNull List<Marker> getMarkersInRect(@NonNull RectF rectangle) { // convert Rectangle to be density depedent float pixelRatio = nativeMapView.getPixelRatio(); @@ -622,6 +623,7 @@ class AnnotationManager { boolean onTap(PointF tapPoint, float screenDensity) { float toleranceSides = 4 * screenDensity; float toleranceTopBottom = 10 * screenDensity; + boolean handledDefaultClick = false; RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides, tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom, @@ -631,7 +633,8 @@ class AnnotationManager { List<Marker> nearbyMarkers = getMarkersInRect(tapRect); long newSelectedMarkerId = -1; - if (nearbyMarkers != null && nearbyMarkers.size() > 0) { + // find a Marker that isn't selected yet + if (nearbyMarkers.size() > 0) { Collections.sort(nearbyMarkers); for (Marker nearbyMarker : nearbyMarkers) { boolean found = false; @@ -647,6 +650,7 @@ class AnnotationManager { } } + // if unselected marker found if (newSelectedMarkerId >= 0) { List<Annotation> annotations = getAnnotations(); int count = annotations.size(); @@ -655,7 +659,6 @@ class AnnotationManager { if (annotation instanceof Marker) { if (annotation.getId() == newSelectedMarkerId) { Marker marker = (Marker) annotation; - boolean handledDefaultClick = false; if (marker instanceof MarkerView) { handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker); @@ -679,6 +682,22 @@ class AnnotationManager { } } } + } else if (nearbyMarkers.size() > 0) { + // we didn't find an unselected marker, check if we can close an already open markers + for (Marker nearbyMarker : nearbyMarkers) { + for (Marker selectedMarker : selectedMarkers) { + if (nearbyMarker.equals(selectedMarker)) { + if (onMarkerClickListener != null) { + // end developer has provided a custom click listener + handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker); + if (!handledDefaultClick) { + deselectMarker(nearbyMarker); + } + } + return true; + } + } + } } return false; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 11dee078ac..0f4d3197cc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.maps; import android.content.Context; import android.graphics.PointF; +import android.location.Location; import android.support.annotation.NonNull; import android.support.v4.view.GestureDetectorCompat; import android.support.v4.view.ScaleGestureDetectorCompat; @@ -15,8 +16,11 @@ 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.constants.MapboxConstants; -import com.mapbox.mapboxsdk.telemetry.MapboxEvent; -import com.mapbox.mapboxsdk.utils.MathUtils; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.services.android.telemetry.MapboxEvent; +import com.mapbox.services.android.telemetry.MapboxTelemetry; +import com.mapbox.services.android.telemetry.utils.MathUtils; +import com.mapbox.services.android.telemetry.utils.TelemetryUtils; /** * Manages gestures events on a MapView. @@ -88,6 +92,18 @@ final class MapGestureDetector { this.focalPoint = focalPoint; } + /** + * Given coordinates from a gesture, use the current projection to translate it into + * a Location object. + * + * @param x coordinate + * @param y coordinate + * @return location + */ + private Location getLocationFromGesture(float x, float y) { + LatLng latLng = projection.fromScreenLocation(new PointF(x, y)); + return TelemetryUtils.buildLocation(latLng.getLongitude(), latLng.getLatitude()); + } /** * Called when user touches the screen, all positions are absolute. @@ -123,8 +139,9 @@ final class MapGestureDetector { && uiSettings.isZoomGesturesEnabled(); if (twoTap) { // Confirmed 2nd Finger Down - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(event.getX(), event.getY()), + MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, transform.getZoom())); } break; @@ -153,7 +170,8 @@ final class MapGestureDetector { // Scroll / Pan Has Stopped if (scrollInProgress) { - MapboxEvent.trackGestureDragEndEvent(projection, event.getX(), event.getY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapDragEndEvent( + getLocationFromGesture(event.getX(), event.getY()), transform.getZoom())); scrollInProgress = false; } @@ -181,7 +199,7 @@ final class MapGestureDetector { */ boolean onGenericMotionEvent(MotionEvent event) { // Mouse events - //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 + // if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { // Choose the action switch (event.getActionMasked()) { @@ -225,7 +243,7 @@ final class MapGestureDetector { @Override public boolean onDoubleTapEvent(MotionEvent e) { - if (!uiSettings.isZoomGesturesEnabled()) { + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled()) { return false; } @@ -252,7 +270,9 @@ final class MapGestureDetector { break; } - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(e.getX(), e.getY()), + MapboxEvent.GESTURE_DOUBLETAP, transform.getZoom())); return true; } @@ -281,8 +301,10 @@ final class MapGestureDetector { } } - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(motionEvent.getX(), motionEvent.getY()), + MapboxEvent.GESTURE_SINGLETAP, transform.getZoom())); + return true; } @@ -333,9 +355,6 @@ final class MapGestureDetector { if (onFlingListener != null) { onFlingListener.onFling(); } - - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY(), transform.getZoom()); return true; } @@ -344,6 +363,9 @@ final class MapGestureDetector { public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (!scrollInProgress) { scrollInProgress = true; + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(e1.getX(), e1.getY()), + MapboxEvent.GESTURE_PAN_START, transform.getZoom())); } if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { return false; @@ -385,8 +407,9 @@ final class MapGestureDetector { scaleGestureOccurred = true; beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(detector.getFocusX(), detector.getFocusY()), + MapboxEvent.GESTURE_PINCH_START, transform.getZoom())); return true; } @@ -476,8 +499,9 @@ final class MapGestureDetector { } beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(detector.getFocusX(), detector.getFocusY()), + MapboxEvent.GESTURE_ROTATION_START, transform.getZoom())); return true; } @@ -556,8 +580,9 @@ final class MapGestureDetector { } beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, - MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent( + getLocationFromGesture(detector.getFocusX(), detector.getFocusY()), + MapboxEvent.GESTURE_PITCH_START, transform.getZoom())); return true; } @@ -654,4 +679,4 @@ final class MapGestureDetector { void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } -}
\ No newline at end of file +} 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 3cb074d209..16b7bf1800 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 @@ -3,25 +3,21 @@ package com.mapbox.mapboxsdk.maps; import android.app.Activity; import android.app.Dialog; import android.app.Fragment; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentFilter; import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.SurfaceTexture; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.CallSuper; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v7.app.AlertDialog; -import android.text.TextUtils; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -45,8 +41,9 @@ import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.maps.widgets.CompassView; 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.net.ConnectivityReceiver; +import com.mapbox.services.android.telemetry.MapboxEvent; +import com.mapbox.services.android.telemetry.MapboxTelemetry; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -72,7 +69,7 @@ public class MapView extends FrameLayout { private NativeMapView nativeMapView; private boolean destroyed; - private boolean hasSurface = false; + private boolean hasSurface; private MapboxMap mapboxMap; private MapCallback mapCallback; @@ -83,8 +80,6 @@ public class MapView extends FrameLayout { private MapKeyListener mapKeyListener; private MapZoomButtonController mapZoomButtonController; - private ConnectivityReceiver connectivityReceiver; - @UiThread public MapView(@NonNull Context context) { super(context); @@ -106,7 +101,7 @@ public class MapView extends FrameLayout { @UiThread public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) { super(context); - initialise(context, options); + initialise(context, options == null ? MapboxMapOptions.createFromAttributes(context, null) : options); } private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) { @@ -127,15 +122,18 @@ public class MapView extends FrameLayout { nativeMapView = new NativeMapView(this); // callback for focal point invalidation - FocalPointInvalidator focalPoint = new FocalPointInvalidator(); + FocalPointInvalidator focalPoint = new FocalPointInvalidator(compassView); // callback for registering touch listeners RegisterTouchListener registerTouchListener = new RegisterTouchListener(); + // callback for zooming in the camera + CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator(); + // setup components for MapboxMap creation Projection proj = new Projection(nativeMapView); UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView)); - TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint); + TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator); MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint); MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer)); AnnotationManager annotations = new AnnotationManager(nativeMapView, this, markerViewManager); @@ -164,7 +162,7 @@ public class MapView extends FrameLayout { setWillNotDraw(false); // notify Map object about current connectivity state - nativeMapView.setReachability(isConnected()); + nativeMapView.setReachability(ConnectivityReceiver.instance(context).isConnected(context)); // initialise MapboxMap mapboxMap.initialise(context, options); @@ -199,10 +197,8 @@ public class MapView extends FrameLayout { */ @UiThread public void onCreate(@Nullable Bundle savedInstanceState) { - nativeMapView.setAccessToken(Mapbox.getAccessToken()); - if (savedInstanceState == null) { - MapboxEvent.trackMapLoadEvent(); + MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapLoadEvent()); } else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) { mapboxMap.onRestoreInstanceState(savedInstanceState); } @@ -234,7 +230,7 @@ public class MapView extends FrameLayout { public void onStart() { onStartCalled = true; mapboxMap.onStart(); - registerConnectivityReceiver(); + ConnectivityReceiver.instance(getContext()).activate(); } /** @@ -264,7 +260,7 @@ public class MapView extends FrameLayout { public void onStop() { onStopCalled = true; mapboxMap.onStop(); - unregisterConnectivityReceiver(); + ConnectivityReceiver.instance(getContext()).deactivate(); } /** @@ -286,18 +282,6 @@ public class MapView extends FrameLayout { nativeMapView = null; } - private void registerConnectivityReceiver() { - getContext().registerReceiver(connectivityReceiver = new ConnectivityReceiver(), - new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - } - - private void unregisterConnectivityReceiver() { - if (connectivityReceiver != null) { - getContext().unregisterReceiver(connectivityReceiver); - connectivityReceiver = null; - } - } - @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { @@ -405,11 +389,6 @@ public class MapView extends FrameLayout { return; } - // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242 - if (TextUtils.isEmpty(nativeMapView.getAccessToken())) { - nativeMapView.setAccessToken(Mapbox.getAccessToken()); - } - nativeMapView.setStyleUrl(url); } @@ -552,30 +531,6 @@ public class MapView extends FrameLayout { } // - // Connectivity events - // - - // This class handles connectivity changes - private class ConnectivityReceiver extends BroadcastReceiver { - - // Called when an action we are listening to in the manifest has been sent - @Override - public void onReceive(Context context, Intent intent) { - if (!destroyed && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - nativeMapView.setReachability(!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)); - } - } - } - - // Called when MapView is being created - private boolean isConnected() { - ConnectivityManager connectivityManager = (ConnectivityManager) - getContext().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); - return (activeNetwork != null) && activeNetwork.isConnectedOrConnecting(); - } - - // // Map events // @@ -663,7 +618,7 @@ public class MapView extends FrameLayout { builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(true); + MapboxTelemetry.getInstance().setTelemetryEnabled(true); dialog.cancel(); } }); @@ -680,7 +635,7 @@ public class MapView extends FrameLayout { builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(false); + MapboxTelemetry.getInstance().setTelemetryEnabled(false); dialog.cancel(); } }); @@ -941,9 +896,18 @@ public class MapView extends FrameLayout { private class FocalPointInvalidator implements FocalPointChangeListener { + private final FocalPointChangeListener[] focalPointChangeListeners; + + FocalPointInvalidator(FocalPointChangeListener... listeners) { + focalPointChangeListeners = listeners; + } + @Override public void onFocalPointChanged(PointF pointF) { mapGestureDetector.setFocalPoint(pointF); + for (FocalPointChangeListener focalPointChangeListener : focalPointChangeListeners) { + focalPointChangeListener.onFocalPointChanged(pointF); + } } } @@ -970,6 +934,16 @@ public class MapView extends FrameLayout { } } + private class CameraZoomInvalidator implements TrackingSettings.CameraZoomInvalidator { + @Override + public void zoomTo(double zoomLevel) { + double currentZoomLevel = mapboxMap.getCameraPosition().zoom; + if (currentZoomLevel < zoomLevel) { + mapboxMap.getTransform().setZoom(zoomLevel); + } + } + } + private static class MapCallback implements OnMapChangedListener { private final MapboxMap mapboxMap; @@ -984,9 +958,14 @@ public class MapView extends FrameLayout { public void onMapChanged(@MapChange int change) { if (change == DID_FINISH_LOADING_STYLE && initialLoad) { initialLoad = false; - mapboxMap.onPreMapReady(); - onMapReady(); - mapboxMap.onPostMapReady(); + new Handler().post(new Runnable() { + @Override + public void run() { + mapboxMap.onPreMapReady(); + onMapReady(); + mapboxMap.onPostMapReady(); + } + }); } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) { mapboxMap.onUpdate(); } 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 9e8073edb8..e3e33ec067 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 @@ -8,6 +8,7 @@ import android.location.Location; import android.os.Bundle; import android.os.Handler; import android.support.annotation.FloatRange; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; @@ -16,7 +17,6 @@ import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; -import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; @@ -38,8 +38,6 @@ import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException; -import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.services.commons.geojson.Feature; @@ -212,6 +210,22 @@ public final class MapboxMap { nativeMapView.setTransitionDelay(delay); } + /** + * Retrieve all the layers in the style + * + * @return all the layers in the current style + */ + @UiThread + public List<Layer> getLayers() { + return nativeMapView.getLayers(); + } + + /** + * Get the layer by id + * + * @param layerId the layer's id + * @return the layer, if present in the style + */ @Nullable @UiThread public Layer getLayer(@NonNull String layerId) { @@ -229,7 +243,7 @@ public final class MapboxMap { @UiThread public <T extends Layer> T getLayerAs(@NonNull String layerId) { try { - //noinspection unchecked + // noinspection unchecked return (T) nativeMapView.getLayer(layerId); } catch (ClassCastException exception) { Timber.e(String.format("Layer: %s is a different type: %s", layerId, exception)); @@ -244,42 +258,95 @@ public final class MapboxMap { */ @UiThread public void addLayer(@NonNull Layer layer) { - addLayer(layer, null); + nativeMapView.addLayer(layer); + } + + /** + * Adds the layer to the map. The layer must be newly created and not added to the map before + * + * @param layer the layer to add + * @param below the layer id to add this layer before + */ + @UiThread + public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { + nativeMapView.addLayerBelow(layer, below); } /** * Adds the layer to the map. The layer must be newly created and not added to the map before * - * @param layer the layer to add - * @param before the layer id to add this layer before + * @param layer the layer to add + * @param above the layer id to add this layer above */ @UiThread - public void addLayer(@NonNull Layer layer, String before) { - nativeMapView.addLayer(layer, before); + public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { + nativeMapView.addLayerAbove(layer, above); + } + + /** + * Adds the layer to the map at the specified index. The layer must be newly + * created and not added to the map before + * + * @param layer the layer to add + * @param index the index to insert the layer at + */ + @UiThread + public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { + nativeMapView.addLayerAt(layer, index); } /** * Removes the layer. Any references to the layer become invalid and should not be used anymore * * @param layerId the layer to remove - * @throws NoSuchLayerException the exception thrown when layer with layerId doesn't exist + * @return the removed layer or null if not found */ @UiThread - public void removeLayer(@NonNull String layerId) throws NoSuchLayerException { - nativeMapView.removeLayer(layerId); + @Nullable + public Layer removeLayer(@NonNull String layerId) { + return nativeMapView.removeLayer(layerId); } /** * Removes the layer. The reference is re-usable after this and can be re-added * * @param layer the layer to remove - * @throws NoSuchLayerException the exeption thrown when the layer doesn't exist + * @return the layer */ @UiThread - public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException { - nativeMapView.removeLayer(layer); + @Nullable + public Layer removeLayer(@NonNull Layer layer) { + return nativeMapView.removeLayer(layer); } + /** + * Removes the layer. Any other references to the layer become invalid and should not be used anymore + * + * @param index the layer index + * @return the removed layer or null if not found + */ + @UiThread + @Nullable + public Layer removeLayerAt(@IntRange(from = 0) int index) { + return nativeMapView.removeLayerAt(index); + } + + /** + * Retrieve all the sources in the style + * + * @return all the sources in the current style + */ + @UiThread + public List<Source> getSources() { + return nativeMapView.getSources(); + } + + /** + * Retrieve a source by id + * + * @param sourceId the source's id + * @return the source if present in the current style + */ @Nullable @UiThread public Source getSource(@NonNull String sourceId) { @@ -297,7 +364,7 @@ public final class MapboxMap { @UiThread public <T extends Source> T getSourceAs(@NonNull String sourceId) { try { - //noinspection unchecked + // noinspection unchecked return (T) nativeMapView.getSource(sourceId); } catch (ClassCastException exception) { Timber.e(String.format("Source: %s is a different type: %s", sourceId, exception)); @@ -319,22 +386,24 @@ public final class MapboxMap { * Removes the source. Any references to the source become invalid and should not be used anymore * * @param sourceId the source to remove - * @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist + * @return the source handle or null if the source was not present */ @UiThread - public void removeSource(@NonNull String sourceId) throws NoSuchSourceException { - nativeMapView.removeSource(sourceId); + @Nullable + public Source removeSource(@NonNull String sourceId) { + return nativeMapView.removeSource(sourceId); } /** * Removes the source, preserving the reverence for re-use * * @param source the source to remove - * @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist + * @return the source */ @UiThread - public void removeSource(@NonNull Source source) throws NoSuchSourceException { - nativeMapView.removeSource(source); + @Nullable + public Source removeSource(@NonNull Source source) { + return nativeMapView.removeSource(source); } /** @@ -515,9 +584,6 @@ public final class MapboxMap { @UiThread public final void moveCamera(CameraUpdate update) { moveCamera(update, null); - // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo` - // invalidate camera position to provide OnCameraChange event. - invalidateCameraPosition(); } /** @@ -534,6 +600,9 @@ public final class MapboxMap { @Override public void run() { transform.moveCamera(MapboxMap.this, update, callback); + // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo` + // invalidate camera position to provide OnCameraChange event. + invalidateCameraPosition(); } }); } @@ -615,7 +684,9 @@ public final class MapboxMap { * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it * will return the current location of the camera in flight. * <p> - * Note that this will cancel location tracking mode if enabled. + * Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling + * {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this + * method and calling it with true in the {@link CancelableCallback#onFinish()}. * </p> * * @param update The change that should be applied to the camera. @@ -629,39 +700,12 @@ public final class MapboxMap { * Do not update or ease the camera from within onCancel(). */ @UiThread - public final void easeCamera( - CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) { - // dismiss tracking, moving camera is equal to a gesture - easeCamera(update, durationMs, easingInterpolator, true, callback); - } - - /** - * 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. - * <p> - * Note that this will cancel location tracking mode if enabled. - * </p> - * - * @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 resetTrackingMode True to reset tracking modes if required, false to ignore - * @param easingInterpolator True for easing interpolator, false for linear. - * @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(). - */ - @UiThread public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, - final boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { + final MapboxMap.CancelableCallback callback) { new Handler().post(new Runnable() { @Override public void run() { - transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, resetTrackingMode, callback); + transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback); } }); } @@ -763,6 +807,21 @@ public final class MapboxMap { transform.resetNorth(); } + /** + * Set focal bearing. + */ + public void setFocalBearing(double bearing, float focalX, float focalY, long duration) { + transform.setBearing(bearing, focalX, focalY, duration); + } + + public float getHeight() { + return nativeMapView.getHeight(); + } + + public float getWidth() { + return nativeMapView.getWidth(); + } + // // Debug // @@ -882,10 +941,6 @@ public final class MapboxMap { private void setStyleUrl(@NonNull MapboxMapOptions options) { String style = options.getStyle(); if (!TextUtils.isEmpty(style)) { - // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242 - if (TextUtils.isEmpty(nativeMapView.getAccessToken())) { - nativeMapView.setAccessToken(Mapbox.getAccessToken()); - } setStyleUrl(style); } } @@ -1604,18 +1659,8 @@ public final class MapboxMap { * @param bitmap A pre-allocated bitmap. */ @UiThread - public void snapshot(@NonNull SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) { - nativeMapView.addSnapshotCallback(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) { - snapshot(callback, null); + nativeMapView.addSnapshotCallback(callback); } /** @@ -2032,4 +2077,4 @@ public final class MapboxMap { Transform getTransform() { return transform; } -}
\ No newline at end of file +} 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 518ef47329..6467033ead 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 @@ -66,6 +66,7 @@ public class MapboxMapOptions implements Parcelable { private boolean tiltGesturesEnabled = true; private boolean zoomGesturesEnabled = true; private boolean zoomControlsEnabled = false; + private boolean doubleTapGesturesEnabled = true; private boolean myLocationEnabled; private Drawable myLocationForegroundDrawable; @@ -116,6 +117,7 @@ public class MapboxMapOptions implements Parcelable { tiltGesturesEnabled = in.readByte() != 0; zoomControlsEnabled = in.readByte() != 0; zoomGesturesEnabled = in.readByte() != 0; + doubleTapGesturesEnabled = in.readByte() != 0; myLocationEnabled = in.readByte() != 0; @@ -184,6 +186,8 @@ public class MapboxMapOptions implements Parcelable { typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiTiltGestures, true)); mapboxMapOptions.zoomControlsEnabled( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiZoomControls, false)); + mapboxMapOptions.doubleTapGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiDoubleTapGestures, true)); mapboxMapOptions.maxZoomPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoomMax, MapboxConstants.MAXIMUM_ZOOM)); @@ -529,6 +533,17 @@ public class MapboxMapOptions implements Parcelable { } /** + * Specifies if the double tap gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + public MapboxMapOptions doubleTapGesturesEnabled(boolean enabled) { + doubleTapGesturesEnabled = enabled; + return this; + } + + /** * Specifies if the user location view is enabled for a map view. * * @param locationEnabled True and gesture will be enabled @@ -809,6 +824,15 @@ public class MapboxMapOptions implements Parcelable { } /** + * Get the current configured double tap gesture state for a map view. + * + * @return True indicates gesture is enabled + */ + public boolean getDoubleTapGesturesEnabled() { + return doubleTapGesturesEnabled; + } + + /** * Get the current configured visibility state for attribution for a map view. * * @return Visibility state of the attribution @@ -987,6 +1011,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (tiltGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (zoomControlsEnabled ? 1 : 0)); dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (myLocationEnabled ? 1 : 0)); @@ -1066,6 +1091,9 @@ public class MapboxMapOptions implements Parcelable { if (zoomControlsEnabled != options.zoomControlsEnabled) { return false; } + if (doubleTapGesturesEnabled != options.doubleTapGesturesEnabled) { + return false; + } if (myLocationEnabled != options.myLocationEnabled) { return false; } @@ -1146,6 +1174,7 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (tiltGesturesEnabled ? 1 : 0); result = 31 * result + (zoomGesturesEnabled ? 1 : 0); result = 31 * result + (zoomControlsEnabled ? 1 : 0); + result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0); result = 31 * result + (myLocationEnabled ? 1 : 0); result = 31 * result + (myLocationForegroundDrawable != null ? myLocationForegroundDrawable.hashCode() : 0); result = 31 * result + (myLocationForegroundBearingDrawable != null @@ -1161,4 +1190,4 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (style != null ? style.hashCode() : 0); return result; } -}
\ No newline at end of file +} 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 0c15480dee..e02a0f3d36 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 @@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.maps; import android.app.ActivityManager; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; @@ -20,10 +20,10 @@ import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; -import com.mapbox.mapboxsdk.offline.OfflineManager; +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException; -import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException; +import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.services.commons.geojson.Feature; @@ -35,6 +35,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import timber.log.Timber; + // Class that wraps the native methods for convenience final class NativeMapView { @@ -42,11 +43,14 @@ final class NativeMapView { private boolean destroyed = false; // Holds the pointer to JNI NativeMapView - private long nativeMapViewPtr = 0; + private long nativePtr = 0; // Used for callbacks private MapView mapView; + //Hold a reference to prevent it from being GC'd as long as it's used on the native side + private final FileSource fileSource; + // Device density private final float pixelRatio; @@ -54,7 +58,7 @@ final class NativeMapView { private CopyOnWriteArrayList<MapView.OnMapChangedListener> onMapChangedListeners; // Listener invoked to return a bitmap of the map - private SnapshotRequest snapshotRequest; + private MapboxMap.SnapshotReadyCallback snapshotReadyCallback; // // Static methods @@ -70,15 +74,9 @@ final class NativeMapView { public NativeMapView(MapView mapView) { Context context = mapView.getContext(); - String dataPath = OfflineManager.getDatabasePath(context); - - // With the availability of offline, we're unifying the ambient (cache) and the offline - // databases to be in the same folder, outside cache, to avoid automatic deletion from - // the system - String cachePath = dataPath; + fileSource = FileSource.getInstance(context); pixelRatio = context.getResources().getDisplayMetrics().density; - String apkPath = context.getPackageCodePath(); int availableProcessors = Runtime.getRuntime().availableProcessors(); ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); @@ -97,7 +95,8 @@ final class NativeMapView { } onMapChangedListeners = new CopyOnWriteArrayList<>(); this.mapView = mapView; - nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory); + + nativeInitialize(this, fileSource, pixelRatio, availableProcessors, totalMemory); } // @@ -114,8 +113,7 @@ final class NativeMapView { } public void destroy() { - nativeDestroy(nativeMapViewPtr); - nativeMapViewPtr = 0; + nativeDestroy(); mapView = null; destroyed = true; } @@ -124,56 +122,56 @@ final class NativeMapView { if (isDestroyedOn("initializeDisplay")) { return; } - nativeInitializeDisplay(nativeMapViewPtr); + nativeInitializeDisplay(); } public void terminateDisplay() { if (isDestroyedOn("terminateDisplay")) { return; } - nativeTerminateDisplay(nativeMapViewPtr); + nativeTerminateDisplay(); } public void initializeContext() { if (isDestroyedOn("initializeContext")) { return; } - nativeInitializeContext(nativeMapViewPtr); + nativeInitializeContext(); } public void terminateContext() { if (isDestroyedOn("terminateContext")) { return; } - nativeTerminateContext(nativeMapViewPtr); + nativeTerminateContext(); } public void createSurface(Surface surface) { if (isDestroyedOn("createSurface")) { return; } - nativeCreateSurface(nativeMapViewPtr, surface); + nativeCreateSurface(surface); } public void destroySurface() { if (isDestroyedOn("destroySurface")) { return; } - nativeDestroySurface(nativeMapViewPtr); + nativeDestroySurface(); } public void update() { if (isDestroyedOn("update")) { return; } - nativeUpdate(nativeMapViewPtr); + nativeUpdate(); } public void render() { if (isDestroyedOn("render")) { return; } - nativeRender(nativeMapViewPtr); + nativeRender(); } public void resizeView(int width, int height) { @@ -204,7 +202,7 @@ final class NativeMapView { + "capping value at 65535 instead of " + height); height = 65535; } - nativeViewResize(nativeMapViewPtr, width, height); + nativeResizeView(width, height); } public void resizeFramebuffer(int fbWidth, int fbHeight) { @@ -228,98 +226,49 @@ final class NativeMapView { throw new IllegalArgumentException( "fbHeight cannot be greater than 65535."); } - nativeFramebufferResize(nativeMapViewPtr, fbWidth, fbHeight); - } - - public void addClass(String clazz) { - if (isDestroyedOn("addClass")) { - return; - } - nativeAddClass(nativeMapViewPtr, clazz); - } - - public void removeClass(String clazz) { - if (isDestroyedOn("removeClass")) { - return; - } - nativeRemoveClass(nativeMapViewPtr, clazz); - } - - public boolean hasClass(String clazz) { - if (isDestroyedOn("hasClass")) { - return false; - } - return nativeHasClass(nativeMapViewPtr, clazz); - } - - public void setClasses(List<String> classes) { - if (isDestroyedOn("setClasses")) { - return; - } - nativeSetClasses(nativeMapViewPtr, classes); - } - - public List<String> getClasses() { - if (isDestroyedOn("getClasses")) { - return new ArrayList<>(); - } - return nativeGetClasses(nativeMapViewPtr); + nativeResizeFramebuffer(fbWidth, fbHeight); } public void setStyleUrl(String url) { if (isDestroyedOn("setStyleUrl")) { return; } - nativeSetStyleUrl(nativeMapViewPtr, url); + nativeSetStyleUrl(url); } public String getStyleUrl() { if (isDestroyedOn("getStyleUrl")) { return null; } - return nativeGetStyleUrl(nativeMapViewPtr); + return nativeGetStyleUrl(); } public void setStyleJson(String newStyleJson) { if (isDestroyedOn("setStyleJson")) { return; } - nativeSetStyleJson(nativeMapViewPtr, newStyleJson); + nativeSetStyleJson(newStyleJson); } public String getStyleJson() { if (isDestroyedOn("getStyleJson")) { return null; } - return nativeGetStyleJson(nativeMapViewPtr); - } - - public void setAccessToken(String accessToken) { - if (isDestroyedOn("setAccessToken")) { - return; - } - nativeSetAccessToken(nativeMapViewPtr, accessToken); - } - - public String getAccessToken() { - if (isDestroyedOn("getAccessToken")) { - return null; - } - return nativeGetAccessToken(nativeMapViewPtr); + return nativeGetStyleJson(); } public void cancelTransitions() { if (isDestroyedOn("cancelTransitions")) { return; } - nativeCancelTransitions(nativeMapViewPtr); + nativeCancelTransitions(); } public void setGestureInProgress(boolean inProgress) { if (isDestroyedOn("setGestureInProgress")) { return; } - nativeSetGestureInProgress(nativeMapViewPtr, inProgress); + nativeSetGestureInProgress(inProgress); } public void moveBy(double dx, double dy) { @@ -333,7 +282,7 @@ final class NativeMapView { if (isDestroyedOn("moveBy")) { return; } - nativeMoveBy(nativeMapViewPtr, dx / pixelRatio, dy / pixelRatio, duration); + nativeMoveBy(dx / pixelRatio, dy / pixelRatio, duration); } public void setLatLng(LatLng latLng) { @@ -347,35 +296,36 @@ final class NativeMapView { if (isDestroyedOn("setLatLng")) { return; } - nativeSetLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude(), duration); + nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration); } public LatLng getLatLng() { if (isDestroyedOn("")) { return new LatLng(); } - return nativeGetLatLng(nativeMapViewPtr); + // wrap longitude values coming from core + return nativeGetLatLng().wrap(); } public void resetPosition() { if (isDestroyedOn("resetPosition")) { return; } - nativeResetPosition(nativeMapViewPtr); + nativeResetPosition(); } public double getPitch() { if (isDestroyedOn("getPitch")) { return 0; } - return nativeGetPitch(nativeMapViewPtr); + return nativeGetPitch(); } public void setPitch(double pitch, long duration) { if (isDestroyedOn("setPitch")) { return; } - nativeSetPitch(nativeMapViewPtr, pitch, duration); + nativeSetPitch(pitch, duration); } public void scaleBy(double ds) { @@ -396,7 +346,7 @@ final class NativeMapView { if (isDestroyedOn("scaleBy")) { return; } - nativeScaleBy(nativeMapViewPtr, ds, cx / pixelRatio, cy / pixelRatio, duration); + nativeScaleBy(ds, cx / pixelRatio, cy / pixelRatio, duration); } public void setScale(double scale) { @@ -417,14 +367,14 @@ final class NativeMapView { if (isDestroyedOn("setScale")) { return; } - nativeSetScale(nativeMapViewPtr, scale, cx / pixelRatio, cy / pixelRatio, duration); + nativeSetScale(scale, cx / pixelRatio, cy / pixelRatio, duration); } public double getScale() { if (isDestroyedOn("getScale")) { return 0; } - return nativeGetScale(nativeMapViewPtr); + return nativeGetScale(); } public void setZoom(double zoom) { @@ -438,49 +388,49 @@ final class NativeMapView { if (isDestroyedOn("setZoom")) { return; } - nativeSetZoom(nativeMapViewPtr, zoom, duration); + nativeSetZoom(zoom, duration); } public double getZoom() { if (isDestroyedOn("getZoom")) { return 0; } - return nativeGetZoom(nativeMapViewPtr); + return nativeGetZoom(); } public void resetZoom() { if (isDestroyedOn("resetZoom")) { return; } - nativeResetZoom(nativeMapViewPtr); + nativeResetZoom(); } public void setMinZoom(double zoom) { if (isDestroyedOn("setMinZoom")) { return; } - nativeSetMinZoom(nativeMapViewPtr, zoom); + nativeSetMinZoom(zoom); } public double getMinZoom() { if (isDestroyedOn("getMinZoom")) { return 0; } - return nativeGetMinZoom(nativeMapViewPtr); + return nativeGetMinZoom(); } public void setMaxZoom(double zoom) { if (isDestroyedOn("setMaxZoom")) { return; } - nativeSetMaxZoom(nativeMapViewPtr, zoom); + nativeSetMaxZoom(zoom); } public double getMaxZoom() { if (isDestroyedOn("getMaxZoom")) { return 0; } - return nativeGetMaxZoom(nativeMapViewPtr); + return nativeGetMaxZoom(); } public void rotateBy(double sx, double sy, double ex, double ey) { @@ -495,14 +445,14 @@ final class NativeMapView { if (isDestroyedOn("rotateBy")) { return; } - nativeRotateBy(nativeMapViewPtr, sx / pixelRatio, sy / pixelRatio, ex, ey, duration); + nativeRotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey, duration); } public void setContentPadding(int[] padding) { if (isDestroyedOn("setContentPadding")) { return; } - nativeSetContentPadding(nativeMapViewPtr, + nativeSetContentPadding( padding[1] / pixelRatio, padding[0] / pixelRatio, padding[3] / pixelRatio, @@ -520,28 +470,35 @@ final class NativeMapView { if (isDestroyedOn("setBearing")) { return; } - nativeSetBearing(nativeMapViewPtr, degrees, duration); + nativeSetBearing(degrees, duration); } public void setBearing(double degrees, double cx, double cy) { if (isDestroyedOn("setBearing")) { return; } - nativeSetBearingXY(nativeMapViewPtr, degrees, cx / pixelRatio, cy / pixelRatio); + setBearing(degrees, cx, cy, 0); + } + + public void setBearing(double degrees, double fx, double fy, long duration) { + if (isDestroyedOn("setBearing")) { + return; + } + nativeSetBearingXY(degrees, fx / pixelRatio, fy / pixelRatio, duration); } public double getBearing() { if (isDestroyedOn("getBearing")) { return 0; } - return nativeGetBearing(nativeMapViewPtr); + return nativeGetBearing(); } public void resetNorth() { if (isDestroyedOn("resetNorth")) { return; } - nativeResetNorth(nativeMapViewPtr); + nativeResetNorth(); } public long addMarker(Marker marker) { @@ -549,14 +506,14 @@ final class NativeMapView { return 0; } Marker[] markers = {marker}; - return nativeAddMarkers(nativeMapViewPtr, markers)[0]; + return nativeAddMarkers(markers)[0]; } public long[] addMarkers(List<Marker> markers) { if (isDestroyedOn("addMarkers")) { return new long[] {}; } - return nativeAddMarkers(nativeMapViewPtr, markers.toArray(new Marker[markers.size()])); + return nativeAddMarkers(markers.toArray(new Marker[markers.size()])); } public long addPolyline(Polyline polyline) { @@ -564,14 +521,14 @@ final class NativeMapView { return 0; } Polyline[] polylines = {polyline}; - return nativeAddPolylines(nativeMapViewPtr, polylines)[0]; + return nativeAddPolylines(polylines)[0]; } public long[] addPolylines(List<Polyline> polylines) { if (isDestroyedOn("addPolylines")) { return new long[] {}; } - return nativeAddPolylines(nativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()])); + return nativeAddPolylines(polylines.toArray(new Polyline[polylines.size()])); } public long addPolygon(Polygon polygon) { @@ -579,14 +536,14 @@ final class NativeMapView { return 0; } Polygon[] polygons = {polygon}; - return nativeAddPolygons(nativeMapViewPtr, polygons)[0]; + return nativeAddPolygons(polygons)[0]; } public long[] addPolygons(List<Polygon> polygons) { if (isDestroyedOn("addPolygons")) { return new long[] {}; } - return nativeAddPolygons(nativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()])); + return nativeAddPolygons(polygons.toArray(new Polygon[polygons.size()])); } public void updateMarker(Marker marker) { @@ -595,21 +552,21 @@ final class NativeMapView { } LatLng position = marker.getPosition(); Icon icon = marker.getIcon(); - nativeUpdateMarker(nativeMapViewPtr, marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId()); + nativeUpdateMarker(marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId()); } public void updatePolygon(Polygon polygon) { if (isDestroyedOn("updatePolygon")) { return; } - nativeUpdatePolygon(nativeMapViewPtr, polygon.getId(), polygon); + nativeUpdatePolygon(polygon.getId(), polygon); } public void updatePolyline(Polyline polyline) { if (isDestroyedOn("updatePolyline")) { return; } - nativeUpdatePolyline(nativeMapViewPtr, polyline.getId(), polyline); + nativeUpdatePolyline(polyline.getId(), polyline); } public void removeAnnotation(long id) { @@ -624,99 +581,106 @@ final class NativeMapView { if (isDestroyedOn("removeAnnotations")) { return; } - nativeRemoveAnnotations(nativeMapViewPtr, ids); + nativeRemoveAnnotations(ids); } public long[] queryPointAnnotations(RectF rect) { if (isDestroyedOn("queryPointAnnotations")) { return new long[] {}; } - return nativeQueryPointAnnotations(nativeMapViewPtr, rect); + return nativeQueryPointAnnotations(rect); } public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) { if (isDestroyedOn("addAnnotationIcon")) { return; } - nativeAddAnnotationIcon(nativeMapViewPtr, symbol, width, height, scale, pixels); + nativeAddAnnotationIcon(symbol, width, height, scale, pixels); } public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) { if (isDestroyedOn("setVisibleCoordinateBounds")) { return; } - nativeSetVisibleCoordinateBounds(nativeMapViewPtr, coordinates, padding, direction, duration); + nativeSetVisibleCoordinateBounds(coordinates, padding, direction, duration); } public void onLowMemory() { if (isDestroyedOn("onLowMemory")) { return; } - nativeOnLowMemory(nativeMapViewPtr); + nativeOnLowMemory(); } public void setDebug(boolean debug) { if (isDestroyedOn("setDebug")) { return; } - nativeSetDebug(nativeMapViewPtr, debug); + nativeSetDebug(debug); } public void cycleDebugOptions() { if (isDestroyedOn("cycleDebugOptions")) { return; } - nativeToggleDebug(nativeMapViewPtr); + nativeCycleDebugOptions(); } public boolean getDebug() { if (isDestroyedOn("getDebug")) { return false; } - return nativeGetDebug(nativeMapViewPtr); + return nativeGetDebug(); + } + + public void setEnableFps(boolean enable) { + if (isDestroyedOn("setEnableFps")) { + return; + } + nativeSetEnableFps(enable); } public boolean isFullyLoaded() { if (isDestroyedOn("isFullyLoaded")) { return false; } - return nativeIsFullyLoaded(nativeMapViewPtr); + return nativeIsFullyLoaded(); } public void setReachability(boolean status) { if (isDestroyedOn("setReachability")) { return; } - nativeSetReachability(nativeMapViewPtr, status); + nativeSetReachability(status); } public double getMetersPerPixelAtLatitude(double lat) { if (isDestroyedOn("getMetersPerPixelAtLatitude")) { return 0; } - return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, getZoom()); + return nativeGetMetersPerPixelAtLatitude(lat, getZoom()); } public ProjectedMeters projectedMetersForLatLng(LatLng latLng) { if (isDestroyedOn("projectedMetersForLatLng")) { return null; } - return nativeProjectedMetersForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + return nativeProjectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude()); } public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) { if (isDestroyedOn("latLngForProjectedMeters")) { return new LatLng(); } - return nativeLatLngForProjectedMeters(nativeMapViewPtr, projectedMeters.getNorthing(), - projectedMeters.getEasting()); + return nativeLatLngForProjectedMeters(projectedMeters.getNorthing(), + projectedMeters.getEasting()).wrap(); } public PointF pixelForLatLng(LatLng latLng) { if (isDestroyedOn("pixelForLatLng")) { return new PointF(); } - PointF pointF = nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + PointF pointF = nativePixelForLatLng(latLng.getLatitude(), latLng.getLongitude()); pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio); return pointF; } @@ -725,21 +689,21 @@ final class NativeMapView { if (isDestroyedOn("latLngForPixel")) { return new LatLng(); } - return nativeLatLngForPixel(nativeMapViewPtr, pixel.x / pixelRatio, pixel.y / pixelRatio); + return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio).wrap(); } public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) { if (isDestroyedOn("getTopOffsetPixelsForAnnotationSymbol")) { return 0; } - return nativeGetTopOffsetPixelsForAnnotationSymbol(nativeMapViewPtr, symbolName); + return nativeGetTopOffsetPixelsForAnnotationSymbol(symbolName); } public void jumpTo(double angle, LatLng center, double pitch, double zoom) { if (isDestroyedOn("jumpTo")) { return; } - nativeJumpTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), pitch, zoom); + nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom); } public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom, @@ -747,7 +711,7 @@ final class NativeMapView { if (isDestroyedOn("easeTo")) { return; } - nativeEaseTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, + nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, easingInterpolator); } @@ -755,115 +719,163 @@ final class NativeMapView { if (isDestroyedOn("flyTo")) { return; } - nativeFlyTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom); + nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom); } public double[] getCameraValues() { if (isDestroyedOn("getCameraValues")) { return new double[] {}; } - return nativeGetCameraValues(nativeMapViewPtr); + return nativeGetCameraValues(); } // Runtime style Api public long getTransitionDuration() { - return nativeGetTransitionDuration(nativeMapViewPtr); + return nativeGetTransitionDuration(); } public void setTransitionDuration(long duration) { - nativeSetTransitionDuration(nativeMapViewPtr, duration); + nativeSetTransitionDuration(duration); } public long getTransitionDelay() { - return nativeGetTransitionDelay(nativeMapViewPtr); + return nativeGetTransitionDelay(); } public void setTransitionDelay(long delay) { - nativeSetTransitionDelay(nativeMapViewPtr, delay); + nativeSetTransitionDelay(delay); + } + + public List<Layer> getLayers() { + if (isDestroyedOn("getLayers")) { + return null; + } + return Arrays.asList(nativeGetLayers()); } public Layer getLayer(String layerId) { if (isDestroyedOn("getLayer")) { return null; } - return nativeGetLayer(nativeMapViewPtr, layerId); + return nativeGetLayer(layerId); } - public void addLayer(@NonNull Layer layer, @Nullable String before) { - if (isDestroyedOn("")) { + public void addLayer(@NonNull Layer layer) { + if (isDestroyedOn("addLayer")) { return; } - nativeAddLayer(nativeMapViewPtr, layer.getNativePtr(), before); + nativeAddLayer(layer.getNativePtr(), null); } - public void removeLayer(@NonNull String layerId) throws NoSuchLayerException { - if (isDestroyedOn("removeLayer")) { + public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { + if (isDestroyedOn("addLayerBelow")) { return; } - nativeRemoveLayerById(nativeMapViewPtr, layerId); + nativeAddLayer(layer.getNativePtr(), below); } - public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException { - if (isDestroyedOn("removeLayer")) { + public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { + if (isDestroyedOn("addLayerAbove")) { + return; + } + nativeAddLayerAbove(layer.getNativePtr(), above); + } + + public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { + if (isDestroyedOn("addLayerAt")) { return; } - nativeRemoveLayer(nativeMapViewPtr, layer.getNativePtr()); + nativeAddLayerAt(layer.getNativePtr(), index); + } + + @Nullable + public Layer removeLayer(@NonNull String layerId) { + if (isDestroyedOn("removeLayer")) { + return null; + } + return nativeRemoveLayerById(layerId); + } + + @Nullable + public Layer removeLayer(@NonNull Layer layer) { + if (isDestroyedOn("removeLayer")) { + return null; + } + nativeRemoveLayer(layer.getNativePtr()); + return layer; + } + + @Nullable + public Layer removeLayerAt(@IntRange(from = 0) int index) { + if (isDestroyedOn("removeLayerAt")) { + return null; + } + return nativeRemoveLayerAt(index); + } + + public List<Source> getSources() { + if (isDestroyedOn("getSources")) { + return null; + } + return Arrays.asList(nativeGetSources()); } public Source getSource(@NonNull String sourceId) { if (isDestroyedOn("getSource")) { return null; } - return nativeGetSource(nativeMapViewPtr, sourceId); + return nativeGetSource(sourceId); } public void addSource(@NonNull Source source) { if (isDestroyedOn("addSource")) { return; } - nativeAddSource(nativeMapViewPtr, source.getNativePtr()); + nativeAddSource(source.getNativePtr()); } - public void removeSource(@NonNull String sourceId) throws NoSuchSourceException { + @Nullable + public Source removeSource(@NonNull String sourceId) { if (isDestroyedOn("removeSource")) { - return; + return null; } - nativeRemoveSourceById(nativeMapViewPtr, sourceId); + return nativeRemoveSourceById(sourceId); } - public void removeSource(@NonNull Source source) throws NoSuchSourceException { + public Source removeSource(@NonNull Source source) { if (isDestroyedOn("removeSource")) { - return; + return null; } - nativeRemoveSource(nativeMapViewPtr, source.getNativePtr()); + nativeRemoveSource(source.getNativePtr()); + return source; } public void addImage(@NonNull String name, @NonNull Bitmap image) { if (isDestroyedOn("addImage")) { return; } - //Check/correct config + // Check/correct config if (image.getConfig() != Bitmap.Config.ARGB_8888) { image = image.copy(Bitmap.Config.ARGB_8888, false); } - //Get pixels + // Get pixels ByteBuffer buffer = ByteBuffer.allocate(image.getByteCount()); image.copyPixelsToBuffer(buffer); - //Determine pixel ratio + // Determine pixel ratio float density = image.getDensity() == Bitmap.DENSITY_NONE ? Bitmap.DENSITY_NONE : image.getDensity(); float pixelRatio = density / DisplayMetrics.DENSITY_DEFAULT; - nativeAddImage(nativeMapViewPtr, name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array()); + nativeAddImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array()); } public void removeImage(String name) { if (isDestroyedOn("removeImage")) { return; } - nativeRemoveImage(nativeMapViewPtr, name); + nativeRemoveImage(name); } // Feature querying @@ -873,7 +885,7 @@ final class NativeMapView { if (isDestroyedOn("queryRenderedFeatures")) { return new ArrayList<>(); } - Feature[] features = nativeQueryRenderedFeaturesForPoint(nativeMapViewPtr, coordinates.x / pixelRatio, + Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio, coordinates.y / pixelRatio, layerIds); return features != null ? Arrays.asList(features) : new ArrayList<Feature>(); } @@ -884,7 +896,7 @@ final class NativeMapView { return new ArrayList<>(); } Feature[] features = nativeQueryRenderedFeaturesForBox( - nativeMapViewPtr, + coordinates.left / pixelRatio, coordinates.top / pixelRatio, coordinates.right / pixelRatio, @@ -897,14 +909,14 @@ final class NativeMapView { if (isDestroyedOn("scheduleTakeSnapshot")) { return; } - nativeScheduleTakeSnapshot(nativeMapViewPtr); + nativeTakeSnapshot(); } public void setApiBaseUrl(String baseUrl) { if (isDestroyedOn("setApiBaseUrl")) { return; } - nativeSetAPIBaseURL(nativeMapViewPtr, baseUrl); + fileSource.setApiBaseUrl(baseUrl); } public float getPixelRatio() { @@ -920,7 +932,9 @@ final class NativeMapView { // protected void onInvalidate() { - mapView.onInvalidate(); + if (mapView != null) { + mapView.onInvalidate(); + } } protected void onMapChanged(int rawChange) { @@ -935,18 +949,9 @@ final class NativeMapView { mapView.onFpsChanged(fps); } - protected void onSnapshotReady(byte[] bytes) { - if (snapshotRequest != null && bytes != null) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inBitmap = snapshotRequest.getBitmap(); // the old Bitmap to be reused - options.inMutable = true; - options.inSampleSize = 1; - Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); - - MapboxMap.SnapshotReadyCallback callback = snapshotRequest.getCallback(); - if (callback != null) { - callback.onSnapshotReady(bitmap); - } + protected void onSnapshotReady(Bitmap bitmap) { + if (snapshotReadyCallback != null && bitmap != null) { + snapshotReadyCallback.onSnapshotReady(bitmap); } } @@ -954,208 +959,192 @@ final class NativeMapView { // JNI methods // - private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio, - int availableProcessors, long totalMemory); - - private native void nativeDestroy(long nativeMapViewPtr); + private native void nativeInitialize(NativeMapView nativeMapView, FileSource fileSource, + float pixelRatio, int availableProcessors, long totalMemory); - private native void nativeInitializeDisplay(long nativeMapViewPtr); + private native void nativeDestroy(); - private native void nativeTerminateDisplay(long nativeMapViewPtr); + private native void nativeInitializeDisplay(); - private native void nativeInitializeContext(long nativeMapViewPtr); + private native void nativeTerminateDisplay(); - private native void nativeTerminateContext(long nativeMapViewPtr); + private native void nativeInitializeContext(); - private native void nativeCreateSurface(long nativeMapViewPtr, - Surface surface); + private native void nativeTerminateContext(); - private native void nativeDestroySurface(long nativeMapViewPtr); + private native void nativeCreateSurface(Object surface); - private native void nativeUpdate(long nativeMapViewPtr); + private native void nativeDestroySurface(); - private native void nativeRender(long nativeMapViewPtr); + private native void nativeUpdate(); - private native void nativeViewResize(long nativeMapViewPtr, int width, int height); + private native void nativeRender(); - private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight); + private native void nativeResizeView(int width, int height); - private native void nativeAddClass(long nativeMapViewPtr, String clazz); + private native void nativeResizeFramebuffer(int fbWidth, int fbHeight); - private native void nativeRemoveClass(long nativeMapViewPtr, String clazz); + private native void nativeSetStyleUrl(String url); - private native boolean nativeHasClass(long nativeMapViewPtr, String clazz); + private native String nativeGetStyleUrl(); - private native void nativeSetClasses(long nativeMapViewPtr, - List<String> classes); + private native void nativeSetStyleJson(String newStyleJson); - private native List<String> nativeGetClasses(long nativeMapViewPtr); + private native String nativeGetStyleJson(); - private native void nativeSetStyleUrl(long nativeMapViewPtr, String url); + private native void nativeCancelTransitions(); - private native String nativeGetStyleUrl(long nativeMapViewPtr); + private native void nativeSetGestureInProgress(boolean inProgress); - private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson); + private native void nativeMoveBy(double dx, double dy, long duration); - private native String nativeGetStyleJson(long nativeMapViewPtr); + private native void nativeSetLatLng(double latitude, double longitude, long duration); - private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken); + private native LatLng nativeGetLatLng(); - private native String nativeGetAccessToken(long nativeMapViewPtr); + private native void nativeResetPosition(); - private native void nativeCancelTransitions(long nativeMapViewPtr); + private native double nativeGetPitch(); - private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress); + private native void nativeSetPitch(double pitch, long duration); - private native void nativeMoveBy(long nativeMapViewPtr, double dx, - double dy, long duration); + private native void nativeScaleBy(double ds, double cx, double cy, long duration); - private native void nativeSetLatLng(long nativeMapViewPtr, double latitude, double longitude, - long duration); + private native void nativeSetScale(double scale, double cx, double cy, long duration); - private native LatLng nativeGetLatLng(long nativeMapViewPtr); + private native double nativeGetScale(); - private native void nativeResetPosition(long nativeMapViewPtr); + private native void nativeSetZoom(double zoom, long duration); - private native double nativeGetPitch(long nativeMapViewPtr); + private native double nativeGetZoom(); - private native void nativeSetPitch(long nativeMapViewPtr, double pitch, long duration); + private native void nativeResetZoom(); - private native void nativeScaleBy(long nativeMapViewPtr, double ds, - double cx, double cy, long duration); + private native void nativeSetMinZoom(double zoom); - private native void nativeSetScale(long nativeMapViewPtr, double scale, - double cx, double cy, long duration); + private native double nativeGetMinZoom(); - private native double nativeGetScale(long nativeMapViewPtr); + private native void nativeSetMaxZoom(double zoom); - private native void nativeSetZoom(long nativeMapViewPtr, double zoom, - long duration); + private native double nativeGetMaxZoom(); - private native double nativeGetZoom(long nativeMapViewPtr); + private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration); - private native void nativeResetZoom(long nativeMapViewPtr); + private native void nativeSetContentPadding(double top, double left, double bottom, double right); - private native void nativeSetMinZoom(long nativeMapViewPtr, double zoom); + private native void nativeSetBearing(double degrees, long duration); - private native double nativeGetMinZoom(long nativeMapViewPtr); + private native void nativeSetBearingXY(double degrees, double fx, double fy, long duration); - private native void nativeSetMaxZoom(long nativeMapViewPtr, double zoom); + private native double nativeGetBearing(); - private native double nativeGetMaxZoom(long nativeMapViewPtr); + private native void nativeResetNorth(); - private native void nativeRotateBy(long nativeMapViewPtr, double sx, - double sy, double ex, double ey, long duration); + private native void nativeUpdateMarker(long markerId, double lat, double lon, String iconId); - private native void nativeSetContentPadding(long nativeMapViewPtr, double top, double left, double bottom, - double right); + private native long[] nativeAddMarkers(Marker[] markers); - private native void nativeSetBearing(long nativeMapViewPtr, double degrees, - long duration); + private native long[] nativeAddPolylines(Polyline[] polylines); - private native void nativeSetBearingXY(long nativeMapViewPtr, double degrees, - double cx, double cy); + private native long[] nativeAddPolygons(Polygon[] polygons); - private native double nativeGetBearing(long nativeMapViewPtr); + private native void nativeRemoveAnnotations(long[] id); - private native void nativeResetNorth(long nativeMapViewPtr); + private native long[] nativeQueryPointAnnotations(RectF rect); - private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId); + private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels); - private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers); + private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, + double direction, long duration); - private native long[] nativeAddPolylines(long nativeMapViewPtr, Polyline[] polylines); + private native void nativeOnLowMemory(); - private native long[] nativeAddPolygons(long nativeMapViewPtr, Polygon[] polygons); + private native void nativeSetDebug(boolean debug); - private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id); + private native void nativeCycleDebugOptions(); - private native long[] nativeQueryPointAnnotations(long nativeMapViewPtr, RectF rect); + private native boolean nativeGetDebug(); - private native void nativeAddAnnotationIcon(long nativeMapViewPtr, String symbol, - int width, int height, float scale, byte[] pixels); + private native void nativeSetEnableFps(boolean enable); - private native void nativeSetVisibleCoordinateBounds(long nativeMapViewPtr, LatLng[] coordinates, - RectF padding, double direction, long duration); + private native boolean nativeIsFullyLoaded(); - private native void nativeOnLowMemory(long nativeMapViewPtr); + private native void nativeSetReachability(boolean status); - private native void nativeSetDebug(long nativeMapViewPtr, boolean debug); + private native double nativeGetMetersPerPixelAtLatitude(double lat, double zoom); - private native void nativeToggleDebug(long nativeMapViewPtr); + private native ProjectedMeters nativeProjectedMetersForLatLng(double latitude, double longitude); - private native boolean nativeGetDebug(long nativeMapViewPtr); + private native LatLng nativeLatLngForProjectedMeters(double northing, double easting); - private native boolean nativeIsFullyLoaded(long nativeMapViewPtr); + private native PointF nativePixelForLatLng(double lat, double lon); - private native void nativeSetReachability(long nativeMapViewPtr, boolean status); + private native LatLng nativeLatLngForPixel(float x, float y); - private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom); + private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName); - private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, double latitude, - double longitude); + private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom); - private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, double northing, double easting); + private native void nativeEaseTo(double angle, double latitude, double longitude, + long duration, double pitch, double zoom, + boolean easingInterpolator); - private native PointF nativePixelForLatLng(long nativeMapViewPtr, double lat, double lon); + private native void nativeFlyTo(double angle, double latitude, double longitude, + long duration, double pitch, double zoom); - private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, float x, float y); + private native double[] nativeGetCameraValues(); - private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName); + private native long nativeGetTransitionDuration(); - private native void nativeJumpTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - double pitch, double zoom); + private native void nativeSetTransitionDuration(long duration); - private native void nativeEaseTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - long duration, double pitch, double zoom, boolean easingInterpolator); + private native long nativeGetTransitionDelay(); - private native void nativeFlyTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - long duration, double pitch, double zoom); + private native void nativeSetTransitionDelay(long delay); - private native double[] nativeGetCameraValues(long nativeMapViewPtr); + private native Layer[] nativeGetLayers(); - private native long nativeGetTransitionDuration(long nativeMapViewPtr); + private native Layer nativeGetLayer(String layerId); - private native void nativeSetTransitionDuration(long nativeMapViewPtr, long duration); + private native void nativeAddLayer(long layerPtr, String before) throws CannotAddLayerException; - private native long nativeGetTransitionDelay(long nativeMapViewPtr); + private native void nativeAddLayerAbove(long layerPtr, String above) throws CannotAddLayerException; - private native void nativeSetTransitionDelay(long nativeMapViewPtr, long delay); + private native void nativeAddLayerAt(long layerPtr, int index) throws CannotAddLayerException; - private native Layer nativeGetLayer(long nativeMapViewPtr, String layerId); + private native Layer nativeRemoveLayerById(String layerId); - private native void nativeAddLayer(long nativeMapViewPtr, long layerPtr, String before); + private native void nativeRemoveLayer(long layerId); - private native void nativeRemoveLayerById(long nativeMapViewPtr, String layerId) throws NoSuchLayerException; + private native Layer nativeRemoveLayerAt(int index); - private native void nativeRemoveLayer(long nativeMapViewPtr, long layerId) throws NoSuchLayerException; + private native Source[] nativeGetSources(); - private native Source nativeGetSource(long nativeMapViewPtr, String sourceId); + private native Source nativeGetSource(String sourceId); - private native void nativeAddSource(long nativeMapViewPtr, long nativeSourcePtr); + private native void nativeAddSource(long nativeSourcePtr) throws CannotAddSourceException; - private native void nativeRemoveSourceById(long nativeMapViewPtr, String sourceId) throws NoSuchSourceException; + private native Source nativeRemoveSourceById(String sourceId); - private native void nativeRemoveSource(long nativeMapViewPtr, long sourcePtr) throws NoSuchSourceException; + private native void nativeRemoveSource(long sourcePtr); - private native void nativeAddImage(long nativeMapViewPtr, String name, int width, int height, float pixelRatio, + private native void nativeAddImage(String name, int width, int height, float pixelRatio, byte[] array); - private native void nativeRemoveImage(long nativeMapViewPtr, String name); + private native void nativeRemoveImage(String name); - private native void nativeUpdatePolygon(long nativeMapViewPtr, long polygonId, Polygon polygon); + private native void nativeUpdatePolygon(long polygonId, Polygon polygon); - private native void nativeUpdatePolyline(long nativeMapviewPtr, long polylineId, Polyline polyline); + private native void nativeUpdatePolyline(long polylineId, Polyline polyline); - private native void nativeScheduleTakeSnapshot(long nativeMapViewPtr); + private native void nativeTakeSnapshot(); - private native Feature[] nativeQueryRenderedFeaturesForPoint(long nativeMapViewPtr, float x, float y, String[] + private native Feature[] nativeQueryRenderedFeaturesForPoint(float x, float y, String[] layerIds); - private native Feature[] nativeQueryRenderedFeaturesForBox(long nativeMapViewPtr, float left, float top, float right, - float bottom, String[] layerIds); - - private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl); + private native Feature[] nativeQueryRenderedFeaturesForBox(float left, float top, + float right, float bottom, + String[] layerIds); int getWidth() { if (isDestroyedOn("")) { @@ -1187,27 +1176,9 @@ final class NativeMapView { // Snapshot // - void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback, @Nullable Bitmap bitmap) { - snapshotRequest = new SnapshotRequest(bitmap, callback); + void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { + snapshotReadyCallback = callback; scheduleTakeSnapshot(); render(); } - - private static class SnapshotRequest { - private Bitmap bitmap; - private MapboxMap.SnapshotReadyCallback callback; - - SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) { - this.bitmap = bitmap; - this.callback = callback; - } - - public Bitmap getBitmap() { - return bitmap; - } - - public MapboxMap.SnapshotReadyCallback getCallback() { - return callback; - } - } } 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 b7f93cc913..82d5dec6a0 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 @@ -117,4 +117,14 @@ public class Projection { float getWidth() { return nativeMapView.getWidth(); } + + /** + * Calculates a zoom level based on minimum scale and current scale from MapView + * + * @param minScale The minimum scale to calculate the zoom level. + * @return zoom level that fits the MapView. + */ + public double calculateZoom(float minScale) { + return Math.log(nativeMapView.getScale() * minScale) / Math.log(2); + } } 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 90d933736b..77fea1a14a 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 @@ -152,4 +152,4 @@ public class SupportMapFragment extends Fragment { public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) { this.onMapReadyCallback = 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 ff8d92d116..38f307f149 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 @@ -1,22 +1,19 @@ package com.mapbox.mapboxsdk.maps; -import android.Manifest; -import android.content.pm.PackageManager; -import android.graphics.PointF; import android.location.Location; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; -import android.support.v4.content.ContextCompat; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; -import com.mapbox.mapboxsdk.location.LocationListener; -import com.mapbox.mapboxsdk.location.LocationServices; +import com.mapbox.mapboxsdk.location.LocationSource; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; +import com.mapbox.services.android.telemetry.location.LocationEngineListener; +import com.mapbox.services.android.telemetry.permissions.PermissionsManager; import timber.log.Timber; @@ -28,20 +25,23 @@ public final class TrackingSettings { private final MyLocationView myLocationView; private final UiSettings uiSettings; private final FocalPointChangeListener focalPointChangedListener; - private LocationListener myLocationListener; + private final CameraZoomInvalidator zoomInvalidator; + private LocationEngineListener myLocationListener; private boolean myLocationEnabled; private boolean dismissLocationTrackingOnGesture = true; private boolean dismissBearingTrackingOnGesture = true; + private boolean isResetTrackingWithCameraPositionChange = true; private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; TrackingSettings(@NonNull MyLocationView myLocationView, UiSettings uiSettings, - FocalPointChangeListener focalPointChangedListener) { + FocalPointChangeListener focalPointChangedListener, CameraZoomInvalidator zoomInvalidator) { this.myLocationView = myLocationView; this.focalPointChangedListener = focalPointChangedListener; this.uiSettings = uiSettings; + this.zoomInvalidator = zoomInvalidator; } void initialise(MapboxMapOptions options) { @@ -54,6 +54,8 @@ public final class TrackingSettings { outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, isDismissLocationTrackingOnGesture()); outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture()); outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled()); + outState.putBoolean(MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA, + isDismissTrackingModesForCameraPositionChange()); } void onRestoreInstanceState(Bundle savedInstanceState) { @@ -62,16 +64,18 @@ public final class TrackingSettings { } catch (SecurityException ignore) { // User did not accept location permissions } - //noinspection ResourceType + // noinspection ResourceType setMyLocationTrackingMode(savedInstanceState.getInt( MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); - //noinspection ResourceType + // noinspection ResourceType setMyBearingTrackingMode(savedInstanceState.getInt( MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); setDismissLocationTrackingOnGesture(savedInstanceState.getBoolean( MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true)); setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean( MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true)); + setDismissTrackingModeForCameraPositionChange(savedInstanceState.getBoolean( + MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA, true)); } /** @@ -92,8 +96,8 @@ public final class TrackingSettings { myLocationView.setMyLocationTrackingMode(myLocationTrackingMode); if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - focalPointChangedListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(), - myLocationView.getCenterY())); + zoomInvalidator.zoomTo(2.0); + focalPointChangedListener.onFocalPointChanged(myLocationView.getCenter()); } else { focalPointChangedListener.onFocalPointChanged(null); } @@ -270,8 +274,39 @@ public final class TrackingSettings { } } + /** + * Reset the tracking modes as necessary. Animated camera position changes can reset the underlying tracking modes. + * + * @param cameraPosition the changed camera position + */ void resetTrackingModesIfRequired(CameraPosition cameraPosition) { - resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1); + if (isDismissTrackingModesForCameraPositionChange()) { + resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1); + } + } + + /** + * Returns if a animation allows to dismiss a tracking mode. + * <p> + * By default this is set to true. + * </p> + * + * @return True if camera animations will allow to dismiss a tracking mode + */ + public boolean isDismissTrackingModesForCameraPositionChange() { + return isResetTrackingWithCameraPositionChange; + } + + /** + * Sets a flag to allow animated camera position changes to dismiss a tracking mode. + * <p> + * <p> + * </p> + * + * @param willAllowToDismiss True will allow animated camera changes dismiss a trackig mode + */ + public void setDismissTrackingModeForCameraPositionChange(boolean willAllowToDismiss) { + isResetTrackingWithCameraPositionChange = willAllowToDismiss; } Location getMyLocation() { @@ -280,7 +315,12 @@ public final class TrackingSettings { void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) { if (listener != null) { - myLocationListener = new LocationListener() { + myLocationListener = new LocationEngineListener() { + @Override + public void onConnected() { + // Nothing + } + @Override public void onLocationChanged(Location location) { if (listener != null) { @@ -288,20 +328,13 @@ public final class TrackingSettings { } } }; - LocationServices.getLocationServices(myLocationView.getContext()).addLocationListener(myLocationListener); + LocationSource.getLocationEngine(myLocationView.getContext()).addLocationEngineListener(myLocationListener); } else { - LocationServices.getLocationServices(myLocationView.getContext()).removeLocationListener(myLocationListener); + LocationSource.getLocationEngine(myLocationView.getContext()).removeLocationEngineListener(myLocationListener); myLocationListener = null; } } - boolean isPermissionsAccepted() { - return (ContextCompat.checkSelfPermission(myLocationView.getContext(), - Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) - || ContextCompat.checkSelfPermission(myLocationView.getContext(), - Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; - } - void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener listener) { this.onMyLocationTrackingModeChangeListener = listener; } @@ -320,7 +353,7 @@ public final class TrackingSettings { } void setMyLocationEnabled(boolean locationEnabled) { - if (!isPermissionsAccepted()) { + if (!PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) { Timber.e("Could not activate user location tracking: " + "user did not accept the permission or permissions were not requested."); return; @@ -343,4 +376,8 @@ public final class TrackingSettings { void onStop() { myLocationView.onStop(); } + + interface CameraZoomInvalidator { + void zoomTo(double zoomLevel); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index 88acc13356..0f6b146907 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -73,7 +73,7 @@ final class Transform implements MapView.OnMapChangedListener { @Override public void onMapChanged(@MapView.MapChange int change) { if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) { - invalidateCameraPosition(); + updateCameraPosition(invalidateCameraPosition()); if (cameraCancelableCallback != null) { cameraCancelableCallback.onFinish(); cameraCancelableCallback = null; @@ -84,47 +84,50 @@ final class Transform implements MapView.OnMapChangedListener { @UiThread final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, MapboxMap.CancelableCallback callback) { - cameraPosition = update.getCameraPosition(mapboxMap); - trackingSettings.resetTrackingModesIfRequired(cameraPosition); - cancelTransitions(); - mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); - if (callback != null) { - callback.onFinish(); + CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); + if (!cameraPosition.equals(this.cameraPosition)) { + trackingSettings.resetTrackingModesIfRequired(cameraPosition); + cancelTransitions(); + mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); + if (callback != null) { + callback.onFinish(); + } } } @UiThread final void easeCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator, - boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { - cameraPosition = update.getCameraPosition(mapboxMap); - if (resetTrackingMode) { + final MapboxMap.CancelableCallback callback) { + CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); + if (!cameraPosition.equals(this.cameraPosition)) { trackingSettings.resetTrackingModesIfRequired(cameraPosition); - } + cancelTransitions(); + if (callback != null) { + cameraCancelableCallback = callback; + mapView.addOnMapChangedListener(this); + } - cancelTransitions(); - if (callback != null) { - cameraCancelableCallback = callback; - mapView.addOnMapChangedListener(this); + mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, + cameraPosition.zoom, easingInterpolator); } - - mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, - cameraPosition.zoom, easingInterpolator); } @UiThread final void animateCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { - cameraPosition = update.getCameraPosition(mapboxMap); - trackingSettings.resetTrackingModesIfRequired(cameraPosition); + CameraPosition cameraPosition = update.getCameraPosition(mapboxMap); + if (!cameraPosition.equals(this.cameraPosition)) { + trackingSettings.resetTrackingModesIfRequired(cameraPosition); - cancelTransitions(); - if (callback != null) { - cameraCancelableCallback = callback; - mapView.addOnMapChangedListener(this); - } + cancelTransitions(); + if (callback != null) { + cameraCancelableCallback = callback; + mapView.addOnMapChangedListener(this); + } - mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, - cameraPosition.zoom); + mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, + cameraPosition.zoom); + } } @UiThread @@ -186,6 +189,10 @@ final class Transform implements MapView.OnMapChangedListener { } } + void setZoom(double zoom) { + mapView.setZoom(zoom); + } + // Direction double getBearing() { double direction = -mapView.getBearing(); @@ -218,6 +225,13 @@ final class Transform implements MapView.OnMapChangedListener { mapView.setBearing(bearing, focalX, focalY); } + void setBearing(double bearing, float focalX, float focalY, long duration) { + if (myLocationView != null) { + myLocationView.setBearing(bearing); + } + mapView.setBearing(bearing, focalX, focalY, duration); + } + // // LatLng / CenterCoordinate 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 bb5271313b..8a3ae1e4f3 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 @@ -48,6 +48,9 @@ public final class UiSettings { private boolean zoomControlsEnabled; + private boolean doubleTapGesturesEnabled = true; + private boolean doubleTapGestureChangeAllowed = true; + private boolean deselectMarkersOnTap = true; private PointF userProvidedFocalPoint; @@ -99,6 +102,8 @@ public final class UiSettings { setTiltGesturesEnabled(options.getTiltGesturesEnabled()); setTiltGestureChangeAllowed(options.getTiltGesturesEnabled()); setZoomControlsEnabled(options.getZoomControlsEnabled()); + setDoubleTapGesturesEnabled(options.getDoubleTapGesturesEnabled()); + setDoubleTapGestureChangeAllowed(options.getDoubleTapGesturesEnabled()); } private void saveGestures(Bundle outState) { @@ -110,6 +115,8 @@ public final class UiSettings { outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE, isRotateGestureChangeAllowed()); outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, isTiltGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE, isTiltGestureChangeAllowed()); + outState.putBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED, isDoubleTapGesturesEnabled()); + outState.putBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED_CHANGE, isDoubleTapGestureChangeAllowed()); } private void restoreGestures(Bundle savedInstanceState) { @@ -121,6 +128,8 @@ public final class UiSettings { setRotateGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE)); setTiltGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED)); setTiltGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE)); + setDoubleTapGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED)); + setDoubleTapGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED_CHANGE)); } private void initialiseCompass(MapboxMapOptions options, Resources resources) { @@ -696,6 +705,41 @@ public final class UiSettings { } /** + * <p> + * Changes whether the user may zoom the map with a double tap. + * </p> + * <p> + * This setting controls only user interactions with the map. If you set the value to false, + * you may still change the map location programmatically. + * </p> + * The default value is true. + * + * @param doubleTapGesturesEnabled If true, zooming with a double tap is enabled. + */ + public void setDoubleTapGesturesEnabled(boolean doubleTapGesturesEnabled) { + if (doubleTapGestureChangeAllowed) { + this.doubleTapGesturesEnabled = doubleTapGesturesEnabled; + } + } + + /** + * Returns whether the user may zoom the map with a double tap. + * + * @return If true, zooming with a double tap is enabled. + */ + public boolean isDoubleTapGesturesEnabled() { + return doubleTapGesturesEnabled; + } + + void setDoubleTapGestureChangeAllowed(boolean doubleTapGestureChangeAllowed) { + this.doubleTapGestureChangeAllowed = doubleTapGestureChangeAllowed; + } + + boolean isDoubleTapGestureChangeAllowed() { + return doubleTapGestureChangeAllowed; + } + + /** * Gets whether the markers are automatically deselected (and therefore, their infowindows * closed) when a map tap is detected. * @@ -771,6 +815,7 @@ public final class UiSettings { setRotateGesturesEnabled(enabled); setTiltGesturesEnabled(enabled); setZoomGesturesEnabled(enabled); + setDoubleTapGesturesEnabled(enabled); } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index dc4a21f2fe..6d8adc1e2a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java @@ -1,17 +1,20 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.content.Context; +import android.graphics.PointF; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; +import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.maps.FocalPointChangeListener; import com.mapbox.mapboxsdk.maps.MapboxMap; import java.lang.ref.WeakReference; @@ -25,15 +28,16 @@ import java.lang.ref.WeakReference; * use {@link com.mapbox.mapboxsdk.maps.UiSettings}. * </p> */ -public final class CompassView extends ImageView implements Runnable { +public final class CompassView extends AppCompatImageView implements Runnable, FocalPointChangeListener { private static final long TIME_WAIT_IDLE = 500; private static final long TIME_FADE_ANIMATION = TIME_WAIT_IDLE; private static final long TIME_MAP_NORTH_ANIMATION = 150; - private double direction = 0.0; + private float rotation = 0.0f; private boolean fadeCompassViewFacingNorth = true; private ViewPropertyAnimatorCompat fadeAnimator; + private PointF focalPoint; public CompassView(Context context) { super(context); @@ -78,8 +82,8 @@ public final class CompassView extends ImageView implements Runnable { } public boolean isFacingNorth() { - // increase range more than just 0.0 - return direction >= 359.0 || direction <= 1.0; + // increase range of facing north to more than only 0.0 + return Math.abs(rotation) >= 359.0 || Math.abs(rotation) <= 1.0; } @Override @@ -96,8 +100,19 @@ public final class CompassView extends ImageView implements Runnable { } } - public void update(final double direction) { - this.direction = direction; + @Nullable + PointF getFocalPoint() { + return focalPoint; + } + + /** + * Updates the direction of the compass. + * + * @param bearing the direction value of the map + */ + public void update(final double bearing) { + // compass needs reverse bearing #8123 + rotation = (float) -bearing; if (!isEnabled()) { return; @@ -115,7 +130,7 @@ public final class CompassView extends ImageView implements Runnable { setVisibility(View.VISIBLE); } - setRotation((float) direction); + setRotation(rotation); } public void fadeCompassViewFacingNorth(boolean compassFadeFacingNorth) { @@ -143,6 +158,11 @@ public final class CompassView extends ImageView implements Runnable { } } + @Override + public void onFocalPointChanged(PointF pointF) { + focalPoint = pointF; + } + static class CompassClickListener implements View.OnClickListener { private WeakReference<MapboxMap> mapboxMap; @@ -158,7 +178,12 @@ public final class CompassView extends ImageView implements Runnable { final MapboxMap mapboxMap = this.mapboxMap.get(); final CompassView compassView = this.compassView.get(); if (mapboxMap != null && compassView != null) { - mapboxMap.resetNorth(); + PointF focalPoint = compassView.getFocalPoint(); + if (focalPoint != null) { + mapboxMap.setFocalBearing(0, focalPoint.x, focalPoint.y, TIME_MAP_NORTH_ANIMATION); + } else { + mapboxMap.setFocalBearing(0, mapboxMap.getWidth() / 2, mapboxMap.getHeight() / 2, TIME_MAP_NORTH_ANIMATION); + } compassView.postDelayed(compassView, TIME_WAIT_IDLE + TIME_MAP_NORTH_ANIMATION); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index c7dd867f2d..2c3685b862 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -31,10 +31,12 @@ 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.location.LocationSource; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.services.android.telemetry.location.LocationEngine; +import com.mapbox.services.android.telemetry.location.LocationEngineListener; +import com.mapbox.services.android.telemetry.location.LocationEnginePriority; import java.lang.ref.WeakReference; @@ -296,7 +298,7 @@ public class MyLocationView extends View { } // draw foreground - if (myBearingTrackingMode == MyBearingTracking.NONE) { + if (myBearingTrackingMode == MyBearingTracking.NONE || !compassListener.isSensorAvailable()) { if (foregroundDrawable != null) { foregroundDrawable.draw(canvas); } @@ -308,8 +310,9 @@ public class MyLocationView extends View { public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) { this.tilt = tilt; if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - mapboxMap.getUiSettings().setFocalPoint(new PointF(getCenterX(), getCenterY())); + mapboxMap.getUiSettings().setFocalPoint(getCenter()); } + invalidate(); } public void setBearing(double bearing) { @@ -319,7 +322,8 @@ public class MyLocationView extends View { if (location != null) { setCompass(location.getBearing() - bearing); } - } else if (myBearingTrackingMode == MyBearingTracking.COMPASS) { + } else if (myBearingTrackingMode == MyBearingTracking.COMPASS + && compassListener.isSensorAvailable()) { setCompass(magneticHeading - bearing); } } @@ -327,13 +331,14 @@ public class MyLocationView extends View { public void setCameraPosition(CameraPosition position) { if (position != null) { - setTilt(position.tilt); setBearing(position.bearing); + setTilt(position.tilt); } } public void onStart() { - if (myBearingTrackingMode == MyBearingTracking.COMPASS) { + if (myBearingTrackingMode == MyBearingTracking.COMPASS + && compassListener.isSensorAvailable()) { compassListener.onResume(); } if (isEnabled()) { @@ -366,8 +371,7 @@ public class MyLocationView extends View { } if (userLocationListener != null) { - LocationServices services = LocationServices.getLocationServices(getContext()); - services.removeLocationListener(userLocationListener); + LocationSource.getLocationEngine(getContext()).removeLocationEngineListener(userLocationListener); userLocationListener = null; } } @@ -417,10 +421,10 @@ public class MyLocationView extends View { * @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()); + LocationEngine locationEngine = LocationSource.getLocationEngine(getContext()); if (enableGps) { // Set an initial location if one available - Location lastLocation = locationServices.getLastLocation(); + Location lastLocation = locationEngine.getLastLocation(); if (lastLocation != null) { setLocation(lastLocation); @@ -430,14 +434,14 @@ public class MyLocationView extends View { userLocationListener = new GpsLocationListener(this); } - locationServices.addLocationListener(userLocationListener); + locationEngine.addLocationEngineListener(userLocationListener); } else { // Disable location and user dot location = null; - locationServices.removeLocationListener(userLocationListener); + locationEngine.removeLocationEngineListener(userLocationListener); } - locationServices.toggleGPS(enableGps); + locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); } public Location getLocation() { @@ -456,7 +460,8 @@ public class MyLocationView extends View { public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { this.myBearingTrackingMode = myBearingTrackingMode; - if (myBearingTrackingMode == MyBearingTracking.COMPASS) { + if (myBearingTrackingMode == MyBearingTracking.COMPASS + && compassListener.isSensorAvailable()) { compassListener.onResume(); } else { compassListener.onPause(); @@ -477,8 +482,19 @@ public class MyLocationView extends View { if (location != null) { if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { // center map directly + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/, - false /*do not disable tracking*/, null); + new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + + } + + @Override + public void onFinish() { + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); + } + }); } else { // do not use interpolated location from tracking mode latLng = null; @@ -528,11 +544,15 @@ public class MyLocationView extends View { directionAnimator.start(); } - public float getCenterX() { + public PointF getCenter() { + return new PointF(getCenterX(), getCenterY()); + } + + private float getCenterX() { return (getX() + getMeasuredWidth()) / 2 + contentPaddingX - projectedX; } - public float getCenterY() { + private float getCenterY() { return (getY() + getMeasuredHeight()) / 2 + contentPaddingY - projectedY; } @@ -541,7 +561,7 @@ public class MyLocationView extends View { contentPaddingY = (padding[1] - padding[3]) / 2; } - private static class GpsLocationListener implements LocationListener { + private static class GpsLocationListener implements LocationEngineListener { private WeakReference<MyLocationView> userLocationView; @@ -549,6 +569,15 @@ public class MyLocationView extends View { userLocationView = new WeakReference<>(myLocationView); } + @Override + public void onConnected() { + MyLocationView locationView = userLocationView.get(); + if (locationView != null) { + Location location = LocationSource.getLocationEngine(locationView.getContext()).getLastLocation(); + locationView.setLocation(location); + } + } + /** * Callback method for receiving location updates from LocationServices. * @@ -587,6 +616,10 @@ public class MyLocationView extends View { sensorManager.unregisterListener(this, rotationVectorSensor); } + public boolean isSensorAvailable() { + return rotationVectorSensor != null; + } + @Override public void onSensorChanged(SensorEvent event) { @@ -619,8 +652,19 @@ public class MyLocationView extends View { private void rotateCamera(float rotation) { CameraPosition.Builder builder = new CameraPosition.Builder(); builder.bearing(rotation); + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), COMPASS_UPDATE_RATE_MS, - false /*linear interpolator*/, false /*do not disable tracking*/, null); + false /*linear interpolator*/, new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + + } + + @Override + public void onFinish() { + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); + } + }); } @Override @@ -734,9 +778,20 @@ public class MyLocationView extends View { // accuracy updateAccuracy(location); + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false); // ease to new camera position with a linear interpolator mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) animationDuration, - false /*linear interpolator*/, false /*do not disable tracking*/, null); + false /*linear interpolator*/, new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + + } + + @Override + public void onFinish() { + mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true); + } + }); } @Override 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 index 6cfbfed733..e9d823ebda 100644 --- 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 @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.maps.widgets; -import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.IntRange; @@ -289,8 +288,7 @@ public class MyLocationViewSettings { private void invalidateFocalPointForTracking(MyLocationView myLocationView) { if (!(myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE)) { - focalPointChangeListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(), - myLocationView.getCenterY())); + focalPointChangeListener.onFocalPointChanged(myLocationView.getCenter()); } else { focalPointChangeListener.onFocalPointChanged(null); } |