diff options
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps')
20 files changed, 720 insertions, 582 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 edf448ab4f..c09c926eb5 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 @@ -118,6 +118,9 @@ class AnnotationManager { if (marker instanceof MarkerView) { markerViewManager.removeMarkerView((MarkerView) marker); + } else { + // do icon cleanup + iconManager.iconCleanup(marker.getIcon()); } } else { // instanceOf Polygon/Polyline @@ -137,6 +140,8 @@ class AnnotationManager { if (marker instanceof MarkerView) { markerViewManager.removeMarkerView((MarkerView) marker); + } else { + iconManager.iconCleanup(marker.getIcon()); } } else { // instanceOf Polygon/Polyline @@ -159,6 +164,8 @@ class AnnotationManager { marker.hideInfoWindow(); if (marker instanceof MarkerView) { markerViewManager.removeMarkerView((MarkerView) marker); + } else { + iconManager.iconCleanup(marker.getIcon()); } } else { // instanceOf Polygon/Polyline diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java index 18eecfd9c3..b1d6df2103 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -7,10 +7,10 @@ import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerView; -import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Responsible for managing icons added to the Map. @@ -25,15 +25,14 @@ import java.util.List; */ class IconManager { - private NativeMapView nativeMapView; - private List<Icon> icons; + private final Map<Icon, Integer> iconMap = new HashMap<>(); + private NativeMapView nativeMapView; private int highestIconWidth; private int highestIconHeight; IconManager(NativeMapView nativeMapView) { this.nativeMapView = nativeMapView; - this.icons = new ArrayList<>(); // load transparent icon for MarkerView to trace actual markers, see #6352 loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP)); } @@ -83,13 +82,13 @@ class IconManager { } private void addIcon(Icon icon, boolean addIconToMap) { - if (!icons.contains(icon)) { - icons.add(icon); + if (!iconMap.keySet().contains(icon)) { + iconMap.put(icon, 1); if (addIconToMap) { loadIcon(icon); } } else { - validateIconChanged(icon); + iconMap.put(icon, iconMap.get(icon) + 1); } } @@ -121,18 +120,11 @@ class IconManager { } void reloadIcons() { - for (Icon icon : icons) { + for (Icon icon : iconMap.keySet()) { loadIcon(icon); } } - private void validateIconChanged(Icon icon) { - Icon oldIcon = icons.get(icons.indexOf(icon)); - if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) { - throw new IconBitmapChangedException(); - } - } - void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) { Icon icon = marker.getIcon(); if (icon == null) { @@ -149,4 +141,23 @@ class IconManager { marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon)); } } + + void iconCleanup(Icon icon) { + int refCounter = iconMap.get(icon) - 1; + if (refCounter == 0) { + remove(icon); + } else { + updateIconRefCounter(icon, refCounter); + } + } + + private void remove(Icon icon) { + nativeMapView.removeAnnotationIcon(icon.getId()); + iconMap.remove(icon); + } + + private void updateIconRefCounter(Icon icon, int refCounter) { + iconMap.put(icon, refCounter); + } + } 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 f456d3ef65..2394e52193 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 @@ -54,8 +54,10 @@ final class MapGestureDetector { private boolean quickZoom; private boolean tiltGestureOccurred; private boolean scrollGestureOccurred; + private boolean scaleGestureOccurred; private boolean recentScaleGestureOccurred; + private long scaleBeginTime; MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, TrackingSettings trackingSettings, AnnotationManager annotationManager, @@ -144,8 +146,8 @@ final class MapGestureDetector { } // Check two finger gestures first - rotateGestureDetector.onTouchEvent(event); scaleGestureDetector.onTouchEvent(event); + rotateGestureDetector.onTouchEvent(event); shoveGestureDetector.onTouchEvent(event); // Handle two finger tap @@ -428,8 +430,7 @@ final class MapGestureDetector { */ private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - long beginTime = 0; - float scaleFactor = 1.0f; + private float scaleFactor = 1.0f; // Called when two fingers first touch the screen @Override @@ -438,9 +439,8 @@ final class MapGestureDetector { return false; } - scaleGestureOccurred = true; recentScaleGestureOccurred = true; - beginTime = detector.getEventTime(); + scaleBeginTime = detector.getEventTime(); MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent( getLocationFromGesture(detector.getFocusX(), detector.getFocusY()), MapboxEvent.GESTURE_PINCH_START, transform)); @@ -451,7 +451,7 @@ final class MapGestureDetector { @Override public void onScaleEnd(ScaleGestureDetector detector) { scaleGestureOccurred = false; - beginTime = 0; + scaleBeginTime = 0; scaleFactor = 1.0f; cameraChangeDispatcher.onCameraIdle(); } @@ -471,7 +471,7 @@ final class MapGestureDetector { // Ignore short touches in case it is a tap // Also ignore small scales long time = detector.getEventTime(); - long interval = time - beginTime; + long interval = time - scaleBeginTime; if (!scaleGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) { return false; } @@ -517,7 +517,6 @@ final class MapGestureDetector { transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), detector.getFocusX(), detector.getFocusY()); } - return true; } } @@ -527,9 +526,11 @@ final class MapGestureDetector { */ private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - long beginTime = 0; - float totalAngle = 0.0f; - boolean started = false; + private static final long ROTATE_INVOKE_WAIT_TIME = 1500; + + private long beginTime = 0; + private float totalAngle = 0.0f; + private boolean started = false; // Called when two fingers first touch the screen @Override @@ -566,7 +567,7 @@ final class MapGestureDetector { // Also ignore small rotate long time = detector.getEventTime(); long interval = time - beginTime; - if (!started && (interval <= ViewConfiguration.getTapTimeout())) { + if (!started && (interval <= ViewConfiguration.getTapTimeout() || isScaleGestureActive(time))) { return false; } @@ -583,6 +584,7 @@ final class MapGestureDetector { if (!started) { return false; } + // rotation constitutes translation of anything except the center of // rotation, so cancel both location and bearing tracking if required trackingSettings.resetTrackingModesIfRequired(true, true, false); @@ -601,6 +603,13 @@ final class MapGestureDetector { } return true; } + + private boolean isScaleGestureActive(long time) { + long scaleExecutionTime = time - scaleBeginTime; + boolean scaleGestureStarted = scaleBeginTime != 0; + boolean scaleOffsetTimeValid = scaleExecutionTime > ROTATE_INVOKE_WAIT_TIME; + return (scaleGestureStarted && scaleOffsetTimeValid) || scaleGestureOccurred; + } } /** 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 848a898f94..12e4c675ee 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 @@ -1,10 +1,9 @@ package com.mapbox.mapboxsdk.maps; import android.content.Context; -import android.graphics.Canvas; import android.graphics.PointF; -import android.graphics.SurfaceTexture; import android.os.Build; +import android.opengl.GLSurfaceView; import android.os.Bundle; import android.support.annotation.CallSuper; import android.support.annotation.IntDef; @@ -16,10 +15,6 @@ import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -32,6 +27,8 @@ import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.egl.EGLConfigChooser; +import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; @@ -45,8 +42,15 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + import timber.log.Timber; +import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION; +import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE; +import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY; + /** * <p> * A {@code MapView} provides an embeddable map interface. @@ -69,10 +73,10 @@ public class MapView extends FrameLayout { private NativeMapView nativeMapView; private MapboxMapOptions mapboxMapOptions; private boolean destroyed; - private boolean hasSurface; private MyLocationView myLocationView; private CompassView compassView; + private PointF focalPoint; private ImageView attrView; private ImageView logoView; @@ -82,6 +86,8 @@ public class MapView extends FrameLayout { private Bundle savedInstanceState; private final CopyOnWriteArrayList<OnMapChangedListener> onMapChangedListeners = new CopyOnWriteArrayList<>(); + private GLSurfaceView glSurfaceView; + @UiThread public MapView(@NonNull Context context) { super(context); @@ -108,8 +114,7 @@ public class MapView extends FrameLayout { private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) { if (isInEditMode()) { - // in IDE, show preview map - LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this); + // in IDE layout editor, just return return; } mapboxMapOptions = options; @@ -133,7 +138,7 @@ public class MapView extends FrameLayout { } else { getViewTreeObserver().removeGlobalOnLayoutListener(this); } - initialiseDrawingSurface(mapboxMapOptions); + initialiseDrawingSurface(); } }); } @@ -143,7 +148,8 @@ public class MapView extends FrameLayout { addOnMapChangedListener(mapCallback); // callback for focal point invalidation - FocalPointInvalidator focalPoint = new FocalPointInvalidator(compassView); + final FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator(); + focalPointInvalidator.addListener(createFocalPointChangeListener()); // callback for registering touch listeners RegisterTouchListener registerTouchListener = new RegisterTouchListener(); @@ -152,13 +158,15 @@ public class MapView extends FrameLayout { CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator(); // callback for camera change events - CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher(); + final CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher(); // setup components for MapboxMap creation Projection proj = new Projection(nativeMapView); - UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, logoView); - TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator); - MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint); + UiSettings uiSettings = new UiSettings(proj, focalPointInvalidator, compassView, attrView, logoView); + TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator, + zoomInvalidator); + MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, + focalPointInvalidator); LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>(); MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer)); IconManager iconManager = new IconManager(nativeMapView); @@ -170,8 +178,11 @@ public class MapView extends FrameLayout { markerViewManager, iconManager, annotations, markers, polygons, polylines); Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings, cameraChangeDispatcher); + mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj, registerTouchListener, annotationManager, cameraChangeDispatcher); + focalPointInvalidator.addListener(mapboxMap.createFocalPointChangeListener()); + mapCallback.attachMapboxMap(mapboxMap); // user input @@ -179,11 +190,13 @@ public class MapView extends FrameLayout { annotationManager, cameraChangeDispatcher); mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings); + mapZoomButtonController = new MapZoomButtonController(new ZoomButtonsController(this)); MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform); - mapZoomButtonController = new MapZoomButtonController(this, uiSettings, zoomListener); + mapZoomButtonController.bind(uiSettings, zoomListener); + compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraChangeDispatcher)); + compassView.setOnClickListener(createCompassClickListener(cameraChangeDispatcher)); // inject widgets with MapboxMap - compassView.setMapboxMap(mapboxMap); myLocationView.setMapboxMap(mapboxMap); attrView.setOnClickListener(new AttributionDialogManager(context, mapboxMap)); @@ -205,6 +218,49 @@ public class MapView extends FrameLayout { } } + private FocalPointChangeListener createFocalPointChangeListener() { + return new FocalPointChangeListener() { + @Override + public void onFocalPointChanged(PointF pointF) { + focalPoint = pointF; + } + }; + } + + private MapboxMap.OnCompassAnimationListener createCompassAnimationListener(final CameraChangeDispatcher + cameraChangeDispatcher) { + return new MapboxMap.OnCompassAnimationListener() { + @Override + public void onCompassAnimation() { + cameraChangeDispatcher.onCameraMove(); + } + + @Override + public void onCompassAnimationFinished() { + compassView.isAnimating(false); + cameraChangeDispatcher.onCameraIdle(); + } + }; + } + + private OnClickListener createCompassClickListener(final CameraChangeDispatcher cameraChangeDispatcher) { + return new OnClickListener() { + @Override + public void onClick(View v) { + if (mapboxMap != null && compassView != null) { + 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); + } + cameraChangeDispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_ANIMATION); + compassView.isAnimating(true); + compassView.postDelayed(compassView, TIME_WAIT_IDLE + TIME_MAP_NORTH_ANIMATION); + } + } + }; + } + // // Lifecycle events // @@ -229,17 +285,36 @@ public class MapView extends FrameLayout { } } - private void initialiseDrawingSurface(MapboxMapOptions mapboxMapOptions) { - if (mapboxMapOptions.getTextureMode()) { - TextureView textureView = new TextureView(getContext()); - textureView.setSurfaceTextureListener(new SurfaceTextureListener()); - addView(textureView, 0); - } else { - SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView); - surfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop()); - surfaceView.getHolder().addCallback(new SurfaceCallback()); - surfaceView.setVisibility(View.VISIBLE); - } + private void initialiseDrawingSurface() { + glSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceView); + glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop()); + glSurfaceView.setEGLContextClientVersion(2); + glSurfaceView.setEGLConfigChooser(new EGLConfigChooser()); + + MapRenderer mapRenderer = new MapRenderer(getContext(), glSurfaceView) { + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + MapView.this.post(new Runnable() { + @Override + public void run() { + // Initialise only once + if (mapboxMap == null) { + initialiseMap(); + mapboxMap.onStart(); + } + } + }); + + super.onSurfaceCreated(gl, config); + } + }; + + glSurfaceView.setRenderer(mapRenderer); + glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY); + glSurfaceView.setVisibility(View.VISIBLE); + + nativeMapView = new NativeMapView(this, mapRenderer); + nativeMapView.resizeView(getMeasuredWidth(), getMeasuredHeight()); } /** @@ -270,7 +345,9 @@ public class MapView extends FrameLayout { */ @UiThread public void onResume() { - // replaced by onStart in v5.0.0 + if (glSurfaceView != null) { + glSurfaceView.onResume(); + } } /** @@ -278,7 +355,9 @@ public class MapView extends FrameLayout { */ @UiThread public void onPause() { - // replaced by onStop in v5.0.0 + if (glSurfaceView != null) { + glSurfaceView.onPause(); + } } /** @@ -296,6 +375,7 @@ public class MapView extends FrameLayout { @UiThread public void onDestroy() { destroyed = true; + mapCallback.clearOnMapReadyCallbacks(); nativeMapView.destroy(); nativeMapView = null; } @@ -359,21 +439,6 @@ public class MapView extends FrameLayout { nativeMapView.onLowMemory(); } - // Called when debug mode is enabled to update a FPS counter - // Called via JNI from NativeMapView - // Forward to any listener - protected void onFpsChanged(final double fps) { - final MapboxMap.OnFpsChangedListener listener = mapboxMap.getOnFpsChangedListener(); - if (listener != null) { - post(new Runnable() { - @Override - public void run() { - listener.onFpsChanged(fps); - } - }); - } - } - /** * <p> * Loads a new map style from the specified URL. @@ -417,29 +482,6 @@ public class MapView extends FrameLayout { // Rendering // - // Called when the map needs to be rerendered - // Called via JNI from NativeMapView - protected void onInvalidate() { - postInvalidate(); - } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (isInEditMode()) { - return; - } - - if (destroyed) { - return; - } - - if (!hasSurface) { - return; - } - nativeMapView.render(); - } - @Override protected void onSizeChanged(int width, int height, int oldw, int oldh) { if (destroyed) { @@ -451,103 +493,6 @@ public class MapView extends FrameLayout { } } - private class SurfaceCallback implements SurfaceHolder.Callback { - - private Surface surface; - - @Override - public void surfaceCreated(SurfaceHolder holder) { - if (nativeMapView == null) { - nativeMapView = new NativeMapView(MapView.this); - nativeMapView.createSurface(surface = holder.getSurface()); - nativeMapView.resizeView(getWidth(), getHeight()); - initialiseMap(); - mapboxMap.onStart(); - } else { - nativeMapView.createSurface(surface = holder.getSurface()); - } - - hasSurface = true; - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - if (destroyed) { - return; - } - nativeMapView.resizeFramebuffer(width, height); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - hasSurface = false; - - if (nativeMapView != null) { - // occurs when activity goes to background - nativeMapView.destroySurface(); - } - surface.release(); - } - } - - // This class handles TextureView callbacks - private class SurfaceTextureListener implements TextureView.SurfaceTextureListener { - - private Surface surface; - - // Called when the native surface texture has been created - // Must do all EGL/GL ES initialization here - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - if (nativeMapView == null) { - nativeMapView = new NativeMapView(MapView.this); - nativeMapView.createSurface(this.surface = new Surface(surface)); - nativeMapView.resizeFramebuffer(width, height); - nativeMapView.resizeView(width, height); - initialiseMap(); - mapboxMap.onStart(); - } else { - nativeMapView.createSurface(this.surface = new Surface(surface)); - } - - hasSurface = true; - } - - // Called when the native surface texture has been destroyed - // Must do all EGL/GL ES destruction here - @Override - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - hasSurface = false; - - if (nativeMapView != null) { - nativeMapView.destroySurface(); - } - this.surface.release(); - return true; - } - - // Called when the format or size of the native surface texture has been changed - // Must handle window resizing here. - @Override - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - if (destroyed) { - return; - } - - nativeMapView.resizeFramebuffer(width, height); - } - - // Called when the SurfaceTexure frame is drawn to screen - // Must sync with UI here - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surface) { - if (destroyed) { - return; - } - mapboxMap.onUpdateRegionChange(); - } - } - // // View events // @@ -557,9 +502,7 @@ public class MapView extends FrameLayout { @CallSuper protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (mapZoomButtonController != null) { - mapZoomButtonController.setVisible(false); - } + mapZoomButtonController.setVisible(false); } // Called when view is hidden and shown @@ -569,7 +512,7 @@ public class MapView extends FrameLayout { return; } - if (mapZoomButtonController != null && nativeMapView != null) { + if (mapZoomButtonController != null) { mapZoomButtonController.setVisible(visibility == View.VISIBLE); } } @@ -583,7 +526,7 @@ public class MapView extends FrameLayout { try { onMapChangedListener.onMapChanged(rawChange); } catch (RuntimeException err) { - Timber.e("Exception (%s) in MapView.OnMapChangedListener: %s", err.getClass(), err.getMessage()); + Timber.e(err, "Exception in MapView.OnMapChangedListener"); } } } @@ -878,10 +821,10 @@ public class MapView extends FrameLayout { private class FocalPointInvalidator implements FocalPointChangeListener { - private final FocalPointChangeListener[] focalPointChangeListeners; + private final List<FocalPointChangeListener> focalPointChangeListeners = new ArrayList<>(); - FocalPointInvalidator(FocalPointChangeListener... listeners) { - focalPointChangeListeners = listeners; + void addListener(FocalPointChangeListener focalPointChangeListener) { + focalPointChangeListeners.add(focalPointChangeListener); } @Override @@ -1016,5 +959,9 @@ public class MapView extends FrameLayout { void addOnMapReadyCallback(OnMapReadyCallback callback) { onMapReadyCallbackList.add(callback); } + + void clearOnMapReadyCallbacks() { + onMapReadyCallbackList.clear(); + } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java index 16513904c5..018c8eb5bb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java @@ -1,7 +1,6 @@ package com.mapbox.mapboxsdk.maps; import android.support.annotation.NonNull; -import android.view.View; import android.widget.ZoomButtonsController; import com.mapbox.mapboxsdk.constants.MapboxConstants; @@ -12,21 +11,25 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants; * Allows single touch only devices to zoom in and out. * </p> */ -final class MapZoomButtonController extends ZoomButtonsController { +final class MapZoomButtonController { private UiSettings uiSettings; + private ZoomButtonsController zoomButtonsController; - MapZoomButtonController(@NonNull View ownerView, @NonNull UiSettings uiSettings, @NonNull OnZoomListener listener) { - super(ownerView); + MapZoomButtonController(@NonNull ZoomButtonsController zoomButtonsController) { + this.zoomButtonsController = zoomButtonsController; + this.zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION); + } + + void bind(UiSettings uiSettings, ZoomButtonsController.OnZoomListener onZoomListener) { this.uiSettings = uiSettings; - setZoomSpeed(MapboxConstants.ANIMATION_DURATION); - setOnZoomListener(listener); + zoomButtonsController.setOnZoomListener(onZoomListener); } - @Override - public void setVisible(boolean visible) { - if (uiSettings.isZoomControlsEnabled()) { - super.setVisible(visible); + void setVisible(boolean visible) { + if (uiSettings != null && !uiSettings.isZoomControlsEnabled()) { + return; } + zoomButtonsController.setVisible(visible); } } 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 f47fcdfd4a..c417b3fc26 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 @@ -44,6 +44,7 @@ import com.mapbox.mapboxsdk.style.light.Light; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.services.android.telemetry.location.LocationEngine; import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.Geometry; import java.lang.reflect.ParameterizedType; import java.util.List; @@ -59,6 +60,7 @@ import timber.log.Timber; * Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread. * </p> */ +@UiThread public final class MapboxMap { private final NativeMapView nativeMapView; @@ -74,6 +76,7 @@ public final class MapboxMap { private final OnRegisterTouchListener onRegisterTouchListener; private MapboxMap.OnFpsChangedListener onFpsChangedListener; + private PointF focalPoint; MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking, MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener, @@ -210,7 +213,6 @@ public final class MapboxMap { * * @return Duration in milliseconds */ - @UiThread public long getTransitionDuration() { return nativeMapView.getTransitionDuration(); } @@ -220,7 +222,6 @@ public final class MapboxMap { * * @param durationMs Duration in milliseconds */ - @UiThread public void setTransitionDuration(long durationMs) { nativeMapView.setTransitionDuration(durationMs); } @@ -233,7 +234,6 @@ public final class MapboxMap { * * @return Delay in milliseconds */ - @UiThread public long getTransitionDelay() { return nativeMapView.getTransitionDelay(); } @@ -243,7 +243,6 @@ public final class MapboxMap { * * @param delayMs Delay in milliseconds */ - @UiThread public void setTransitionDelay(long delayMs) { nativeMapView.setTransitionDelay(delayMs); } @@ -263,7 +262,6 @@ public final class MapboxMap { * * @param enable true to enable */ - @UiThread public void setPrefetchesTiles(boolean enable) { nativeMapView.setPrefetchesTiles(enable); } @@ -272,10 +270,8 @@ public final class MapboxMap { * Check whether tile pre-fetching is enabled or not. * * @return true if enabled - * * @see MapboxMap#setPrefetchesTiles(boolean) */ - @UiThread public boolean getPrefetchesTiles() { return nativeMapView.getPrefetchesTiles(); } @@ -285,7 +281,6 @@ public final class MapboxMap { * * @return all the layers in the current style */ - @UiThread public List<Layer> getLayers() { return nativeMapView.getLayers(); } @@ -297,7 +292,6 @@ public final class MapboxMap { * @return the layer, if present in the style */ @Nullable - @UiThread public Layer getLayer(@NonNull String layerId) { return nativeMapView.getLayer(layerId); } @@ -310,13 +304,12 @@ public final class MapboxMap { * @return the casted Layer, null if another type */ @Nullable - @UiThread public <T extends Layer> T getLayerAs(@NonNull String layerId) { try { // noinspection unchecked return (T) nativeMapView.getLayer(layerId); } catch (ClassCastException exception) { - Timber.e(String.format("Layer: %s is a different type: %s", layerId, exception)); + Timber.e(exception, "Layer: %s is a different type: ", layerId); return null; } } @@ -326,7 +319,6 @@ public final class MapboxMap { * * @param layer the layer to add */ - @UiThread public void addLayer(@NonNull Layer layer) { nativeMapView.addLayer(layer); } @@ -337,7 +329,6 @@ public final class MapboxMap { * @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); } @@ -348,7 +339,6 @@ public final class MapboxMap { * @param layer the layer to add * @param above the layer id to add this layer above */ - @UiThread public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { nativeMapView.addLayerAbove(layer, above); } @@ -360,7 +350,6 @@ public final class MapboxMap { * @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); } @@ -371,7 +360,6 @@ public final class MapboxMap { * @param layerId the layer to remove * @return the removed layer or null if not found */ - @UiThread @Nullable public Layer removeLayer(@NonNull String layerId) { return nativeMapView.removeLayer(layerId); @@ -383,7 +371,6 @@ public final class MapboxMap { * @param layer the layer to remove * @return the layer */ - @UiThread @Nullable public Layer removeLayer(@NonNull Layer layer) { return nativeMapView.removeLayer(layer); @@ -395,7 +382,6 @@ public final class MapboxMap { * @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); @@ -406,7 +392,6 @@ public final class MapboxMap { * * @return all the sources in the current style */ - @UiThread public List<Source> getSources() { return nativeMapView.getSources(); } @@ -418,7 +403,6 @@ public final class MapboxMap { * @return the source if present in the current style */ @Nullable - @UiThread public Source getSource(@NonNull String sourceId) { return nativeMapView.getSource(sourceId); } @@ -431,13 +415,12 @@ public final class MapboxMap { * @return the casted Source, null if another type */ @Nullable - @UiThread public <T extends Source> T getSourceAs(@NonNull String sourceId) { try { // noinspection unchecked return (T) nativeMapView.getSource(sourceId); } catch (ClassCastException exception) { - Timber.e(String.format("Source: %s is a different type: %s", sourceId, exception)); + Timber.e(exception, "Source: %s is a different type: ", sourceId); return null; } } @@ -447,7 +430,6 @@ public final class MapboxMap { * * @param source the source to add */ - @UiThread public void addSource(@NonNull Source source) { nativeMapView.addSource(source); } @@ -458,7 +440,6 @@ public final class MapboxMap { * @param sourceId the source to remove * @return the source handle or null if the source was not present */ - @UiThread @Nullable public Source removeSource(@NonNull String sourceId) { return nativeMapView.removeSource(sourceId); @@ -470,7 +451,6 @@ public final class MapboxMap { * @param source the source to remove * @return the source */ - @UiThread @Nullable public Source removeSource(@NonNull Source source) { return nativeMapView.removeSource(source); @@ -482,7 +462,6 @@ public final class MapboxMap { * @param name the name of the image * @param image the pre-multiplied Bitmap */ - @UiThread public void addImage(@NonNull String name, @NonNull Bitmap image) { nativeMapView.addImage(name, image); } @@ -492,11 +471,14 @@ public final class MapboxMap { * * @param name the name of the image to remove */ - @UiThread public void removeImage(String name) { nativeMapView.removeImage(name); } + public Bitmap getImage(@NonNull String name) { + return nativeMapView.getImage(name); + } + // // MinZoom // @@ -508,7 +490,6 @@ public final class MapboxMap { * * @param minZoom The new minimum zoom level. */ - @UiThread public void setMinZoomPreference( @FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { transform.setMinZoom(minZoom); @@ -516,12 +497,11 @@ public final class MapboxMap { /** * <p> - * Gets the maximum zoom level the map can be displayed at. + * Gets the minimum zoom level the map can be displayed at. * </p> * * @return The minimum zoom level. */ - @UiThread public double getMinZoomLevel() { return transform.getMinZoom(); } @@ -534,10 +514,12 @@ public final class MapboxMap { * <p> * Sets the maximum zoom level the map can be displayed at. * </p> + * <p> + * The default maximum zoomn level is 22. The upper bound for this value is 25.5. + * </p> * * @param maxZoom The new maximum zoom level. */ - @UiThread public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { transform.setMaxZoom(maxZoom); @@ -550,7 +532,6 @@ public final class MapboxMap { * * @return The maximum zoom level. */ - @UiThread public double getMaxZoomLevel() { return transform.getMaxZoom(); } @@ -576,7 +557,10 @@ public final class MapboxMap { * Gets the tracking interface settings for the map. * * @return the TrackingSettings asssociated with this map + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ + @Deprecated public TrackingSettings getTrackingSettings() { return trackingSettings; } @@ -589,7 +573,10 @@ public final class MapboxMap { * Gets the settings of the user location for the map. * * @return the MyLocationViewSettings associated with this map + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ + @Deprecated public MyLocationViewSettings getMyLocationViewSettings() { return myLocationViewSettings; } @@ -627,6 +614,47 @@ public final class MapboxMap { // /** + * Moves the center of the screen to a latitude and longitude specified by a LatLng object. This centers the + * camera on the LatLng object. + * + * @param latLng Target location to change to + */ + public void setLatLng(@NonNull LatLng latLng) { + nativeMapView.setLatLng(latLng); + } + + /** + * Moves the camera viewpoint to a particular zoom level. + * + * @param zoom Zoom level to change to + */ + public void setZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double zoom) { + if (focalPoint == null) { + focalPoint = new PointF(nativeMapView.getWidth() / 2, nativeMapView.getHeight() / 2); + } + nativeMapView.setZoom(zoom, focalPoint, 0); + } + + /** + * Moves the camera viewpoint angle to a particular angle in degrees. + * + * @param tilt Tilt angle to change to + */ + public void setTilt(@FloatRange(from = MapboxConstants.MINIMUM_TILT, to = MapboxConstants.MAXIMUM_TILT) double tilt) { + nativeMapView.setPitch(tilt, 0); + } + + /** + * Moves the camera viewpoint direction to a particular angle in degrees. + * + * @param bearing Direction angle to change to + */ + public void setBearing(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) + double bearing) { + nativeMapView.setBearing(bearing); + } + + /** * Cancels ongoing animations. * <p> * This invokes the {@link CancelableCallback} for ongoing camera updates. @@ -665,7 +693,6 @@ public final class MapboxMap { * * @param update The change that should be applied to the camera. */ - @UiThread public final void moveCamera(CameraUpdate update) { moveCamera(update, null); } @@ -678,7 +705,6 @@ public final class MapboxMap { * @param update The change that should be applied to the camera * @param callback the callback to be invoked when an animation finishes or is canceled */ - @UiThread public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) { new Handler().post(new Runnable() { @Override @@ -699,7 +725,6 @@ public final class MapboxMap { * @param update The change that should be applied to the camera. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void easeCamera(CameraUpdate update) { easeCamera(update, MapboxConstants.ANIMATION_DURATION); } @@ -714,7 +739,6 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void easeCamera(CameraUpdate update, int durationMs) { easeCamera(update, durationMs, null); } @@ -738,7 +762,6 @@ public final class MapboxMap { * Do not update or ease the camera from within onCancel(). * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { easeCamera(update, durationMs, true, callback); } @@ -757,7 +780,6 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @param easingInterpolator True for easing interpolator, false for linear. */ - @UiThread public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) { easeCamera(update, durationMs, easingInterpolator, null); } @@ -783,7 +805,6 @@ public final class MapboxMap { * 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 MapboxMap.CancelableCallback callback) { easeCamera(update, durationMs, easingInterpolator, callback, false); @@ -811,7 +832,6 @@ public final class MapboxMap { * Do not update or ease the camera from within onCancel(). * @param isDismissable true will allow animated camera changes dismiss a tracking mode. */ - @UiThread public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, final MapboxMap.CancelableCallback callback, final boolean isDismissable) { new Handler().post(new Runnable() { @@ -831,7 +851,6 @@ public final class MapboxMap { * @param update The change that should be applied to the camera. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void animateCamera(CameraUpdate update) { animateCamera(update, MapboxConstants.ANIMATION_DURATION, null); } @@ -848,7 +867,6 @@ public final class MapboxMap { * called. Do not update or animate the camera from within onCancel(). * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback); } @@ -864,7 +882,6 @@ public final class MapboxMap { * positive, otherwise an IllegalArgumentException will be thrown. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void animateCamera(CameraUpdate update, int durationMs) { animateCamera(update, durationMs, null); } @@ -887,7 +904,6 @@ public final class MapboxMap { * isn't required, leave it as null. * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ - @UiThread public final void animateCamera(final CameraUpdate update, final int durationMs, final MapboxMap.CancelableCallback callback) { new Handler().post(new Runnable() { @@ -958,7 +974,6 @@ public final class MapboxMap { * * @return If true, map debug information is currently shown. */ - @UiThread public boolean isDebugActive() { return nativeMapView.getDebug(); } @@ -971,7 +986,6 @@ public final class MapboxMap { * * @param debugActive If true, map debug information is shown. */ - @UiThread public void setDebugActive(boolean debugActive) { nativeMapView.setDebug(debugActive); } @@ -985,7 +999,6 @@ public final class MapboxMap { * * @see #isDebugActive() */ - @UiThread public void cycleDebugOptions() { nativeMapView.cycleDebugOptions(); } @@ -1035,7 +1048,6 @@ public final class MapboxMap { * @param url The URL of the map style * @see Style */ - @UiThread public void setStyleUrl(@NonNull String url) { setStyleUrl(url, null); } @@ -1068,7 +1080,6 @@ public final class MapboxMap { * @param callback The callback that is invoked when the style has loaded. * @see Style */ - @UiThread public void setStyleUrl(@NonNull final String url, @Nullable final OnStyleLoadedListener callback) { if (callback != null) { nativeMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { @@ -1100,7 +1111,6 @@ public final class MapboxMap { * @param style The bundled style. * @see Style */ - @UiThread public void setStyle(@Style.StyleUrl String style) { setStyleUrl(style); } @@ -1117,7 +1127,6 @@ public final class MapboxMap { * @param callback The callback to be invoked when the style has finished loading * @see Style */ - @UiThread public void setStyle(@Style.StyleUrl String style, @Nullable OnStyleLoadedListener callback) { setStyleUrl(style, callback); } @@ -1135,16 +1144,36 @@ public final class MapboxMap { } /** - * Returns the map style currently displayed in the map view. + * Returns the map style url currently displayed in the map view. * * @return The URL of the map style */ - @UiThread @Nullable public String getStyleUrl() { return nativeMapView.getStyleUrl(); } + /** + * Loads a new map style from a json string. + * <p> + * If the style fails to load or an invalid style URL is set, the map view will become blank. + * An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be + * sent. + * </p> + */ + public void setStyleJson(@NonNull String styleJson) { + nativeMapView.setStyleJson(styleJson); + } + + /** + * Returns the map style json currently displayed in the map view. + * + * @return The json of the map style + */ + public String getStyleJson() { + return nativeMapView.getStyleJson(); + } + // // Annotations // @@ -1159,7 +1188,6 @@ public final class MapboxMap { * @param markerOptions A marker options object that defines how to render the marker * @return The {@code Marker} that was added to the map */ - @UiThread @NonNull public Marker addMarker(@NonNull MarkerOptions markerOptions) { return annotationManager.addMarker(markerOptions, this); @@ -1175,7 +1203,6 @@ public final class MapboxMap { * @param markerOptions A marker options object that defines how to render the marker * @return The {@code Marker} that was added to the map */ - @UiThread @NonNull public Marker addMarker(@NonNull BaseMarkerOptions markerOptions) { return annotationManager.addMarker(markerOptions, this); @@ -1190,9 +1217,11 @@ public final class MapboxMap { * * @param markerOptions A marker options object that defines how to render the marker * @return The {@code Marker} that was added to the map + * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android + * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java */ - @UiThread @NonNull + @Deprecated public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions) { return annotationManager.addMarker(markerOptions, this, null); } @@ -1207,8 +1236,10 @@ public final class MapboxMap { * @param markerOptions A marker options object that defines how to render the marker * @param onMarkerViewAddedListener Callback invoked when the View has been added to the map * @return The {@code Marker} that was added to the map + * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android + * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java */ - @UiThread + @Deprecated @NonNull public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, final MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) { @@ -1224,9 +1255,11 @@ public final class MapboxMap { * * @param markerViewOptions A list of markerView options objects that defines how to render the markers * @return A list of the {@code MarkerView}s that were added to the map + * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android + * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java */ - @UiThread @NonNull + @Deprecated public List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions) { return annotationManager.addMarkerViews(markerViewOptions, this); @@ -1237,9 +1270,11 @@ public final class MapboxMap { * * @param rect the rectangular area on the map to query for markerViews * @return A list of the markerViews that were found in the rectangle + * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android + * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java */ - @UiThread @NonNull + @Deprecated public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) { return annotationManager.getMarkerViewsInRect(rect); } @@ -1254,7 +1289,6 @@ public final class MapboxMap { * @param markerOptionsList A list of marker options objects that defines how to render the markers * @return A list of the {@code Marker}s that were added to the map */ - @UiThread @NonNull public List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList) { @@ -1268,7 +1302,6 @@ public final class MapboxMap { * * @param updatedMarker An updated marker object */ - @UiThread public void updateMarker(@NonNull Marker updatedMarker) { annotationManager.updateMarker(updatedMarker, this); } @@ -1279,7 +1312,6 @@ public final class MapboxMap { * @param polylineOptions A polyline options object that defines how to render the polyline * @return The {@code Polyine} that was added to the map */ - @UiThread @NonNull public Polyline addPolyline(@NonNull PolylineOptions polylineOptions) { return annotationManager.addPolyline(polylineOptions, this); @@ -1291,7 +1323,6 @@ public final class MapboxMap { * @param polylineOptionsList A list of polyline options objects that defines how to render the polylines. * @return A list of the {@code Polyline}s that were added to the map. */ - @UiThread @NonNull public List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList) { return annotationManager.addPolylines(polylineOptionsList, this); @@ -1302,7 +1333,6 @@ public final class MapboxMap { * * @param polyline An updated polyline object. */ - @UiThread public void updatePolyline(Polyline polyline) { annotationManager.updatePolyline(polyline); } @@ -1313,7 +1343,6 @@ public final class MapboxMap { * @param polygonOptions A polygon options object that defines how to render the polygon. * @return The {@code Polygon} that was added to the map. */ - @UiThread @NonNull public Polygon addPolygon(@NonNull PolygonOptions polygonOptions) { return annotationManager.addPolygon(polygonOptions, this); @@ -1325,7 +1354,6 @@ public final class MapboxMap { * @param polygonOptionsList A list of polygon options objects that defines how to render the polygons * @return A list of the {@code Polygon}s that were added to the map */ - @UiThread @NonNull public List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList) { return annotationManager.addPolygons(polygonOptionsList, this); @@ -1336,7 +1364,6 @@ public final class MapboxMap { * * @param polygon An updated polygon object */ - @UiThread public void updatePolygon(Polygon polygon) { annotationManager.updatePolygon(polygon); } @@ -1349,7 +1376,6 @@ public final class MapboxMap { * * @param marker Marker to remove */ - @UiThread public void removeMarker(@NonNull Marker marker) { annotationManager.removeAnnotation(marker); } @@ -1362,7 +1388,6 @@ public final class MapboxMap { * * @param polyline Polyline to remove */ - @UiThread public void removePolyline(@NonNull Polyline polyline) { annotationManager.removeAnnotation(polyline); } @@ -1375,7 +1400,6 @@ public final class MapboxMap { * * @param polygon Polygon to remove */ - @UiThread public void removePolygon(@NonNull Polygon polygon) { annotationManager.removeAnnotation(polygon); } @@ -1385,7 +1409,6 @@ public final class MapboxMap { * * @param annotation The annotation object to remove. */ - @UiThread public void removeAnnotation(@NonNull Annotation annotation) { annotationManager.removeAnnotation(annotation); } @@ -1395,7 +1418,6 @@ public final class MapboxMap { * * @param id The identifier associated to the annotation to be removed */ - @UiThread public void removeAnnotation(long id) { annotationManager.removeAnnotation(id); } @@ -1405,7 +1427,6 @@ public final class MapboxMap { * * @param annotationList A list of annotation objects to remove. */ - @UiThread public void removeAnnotations(@NonNull List<? extends Annotation> annotationList) { annotationManager.removeAnnotations(annotationList); } @@ -1413,7 +1434,6 @@ public final class MapboxMap { /** * Removes all annotations from the map. */ - @UiThread public void removeAnnotations() { annotationManager.removeAnnotations(); } @@ -1421,7 +1441,6 @@ public final class MapboxMap { /** * Removes all markers, polylines, polygons, overlays, etc from the map. */ - @UiThread public void clear() { annotationManager.removeAnnotations(); } @@ -1487,7 +1506,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user clicks on a marker. * To unset the callback, use null. */ - @UiThread public void setOnMarkerClickListener(@Nullable OnMarkerClickListener listener) { annotationManager.setOnMarkerClickListener(listener); } @@ -1498,7 +1516,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user clicks on a polygon. * To unset the callback, use null. */ - @UiThread public void setOnPolygonClickListener(@Nullable OnPolygonClickListener listener) { annotationManager.setOnPolygonClickListener(listener); } @@ -1509,7 +1526,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user clicks on a polyline. * To unset the callback, use null. */ - @UiThread public void setOnPolylineClickListener(@Nullable OnPolylineClickListener listener) { annotationManager.setOnPolylineClickListener(listener); } @@ -1524,7 +1540,6 @@ public final class MapboxMap { * * @param marker The marker to select. */ - @UiThread public void selectMarker(@NonNull Marker marker) { if (marker == null) { Timber.w("marker was null, so just returning"); @@ -1536,7 +1551,6 @@ public final class MapboxMap { /** * Deselects any currently selected marker. All markers will have it's info window closed. */ - @UiThread public void deselectMarkers() { annotationManager.deselectMarkers(); } @@ -1546,7 +1560,6 @@ public final class MapboxMap { * * @param marker the marker to deselect */ - @UiThread public void deselectMarker(@NonNull Marker marker) { annotationManager.deselectMarker(marker); } @@ -1556,7 +1569,6 @@ public final class MapboxMap { * * @return The currently selected marker. */ - @UiThread public List<Marker> getSelectedMarkers() { return annotationManager.getSelectedMarkers(); } @@ -1584,7 +1596,6 @@ public final class MapboxMap { * @param infoWindowAdapter The callback to be invoked when an info window will be shown. * To unset the callback, use null. */ - @UiThread public void setInfoWindowAdapter(@Nullable InfoWindowAdapter infoWindowAdapter) { annotationManager.getInfoWindowManager().setInfoWindowAdapter(infoWindowAdapter); } @@ -1594,7 +1605,6 @@ public final class MapboxMap { * * @return The callback to be invoked when an info window will be shown. */ - @UiThread @Nullable public InfoWindowAdapter getInfoWindowAdapter() { return annotationManager.getInfoWindowManager().getInfoWindowAdapter(); @@ -1605,7 +1615,6 @@ public final class MapboxMap { * * @param allow If true, map allows concurrent multiple infowindows to be shown. */ - @UiThread public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { annotationManager.getInfoWindowManager().setAllowConcurrentMultipleOpenInfoWindows(allow); } @@ -1615,7 +1624,6 @@ public final class MapboxMap { * * @return If true, map allows concurrent multiple infowindows to be shown. */ - @UiThread public boolean isAllowConcurrentMultipleOpenInfoWindows() { return annotationManager.getInfoWindowManager().isAllowConcurrentMultipleOpenInfoWindows(); } @@ -1659,6 +1667,30 @@ public final class MapboxMap { return cameraPosition; } + /** + * Get a camera position that fits a provided shape with a given bearing and padding. + * + * @param geometry the geometry to constrain the map with + * @param bearing the bearing at which to compute the geometry's bounds + * @param padding the padding to apply to the bounds + * @return the camera position that fits the bounds and padding + */ + public CameraPosition getCameraForGeometry(Geometry geometry, double bearing, int[] padding) { + // calculate and set additional bounds padding + int[] mapPadding = getPadding(); + for (int i = 0; i < padding.length; i++) { + padding[i] = mapPadding[i] + padding[i]; + } + projection.setContentPadding(padding, myLocationViewSettings.getPadding()); + + // get padded camera position from LatLngBounds + CameraPosition cameraPosition = nativeMapView.getCameraForGeometry(geometry, bearing); + + // reset map padding + setPadding(mapPadding); + return cameraPosition; + } + // // Padding // @@ -1709,7 +1741,6 @@ public final class MapboxMap { * @param listener The callback that's invoked on every camera change position. * To unset the callback, use null. */ - @UiThread @Deprecated public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) { transform.setOnCameraChangeListener(listener); @@ -1720,7 +1751,6 @@ public final class MapboxMap { * * @param listener the listener to notify */ - @UiThread public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) { cameraChangeDispatcher.setOnCameraIdleListener(listener); } @@ -1730,7 +1760,6 @@ public final class MapboxMap { * * @param listener the listener to notify */ - @UiThread public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) { cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener); } @@ -1740,8 +1769,7 @@ public final class MapboxMap { * * @param listener the listener to notify */ - @UiThread - public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) { + public void setOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) { cameraChangeDispatcher.setOnCameraMoveStartedListener(listener); } @@ -1750,7 +1778,6 @@ public final class MapboxMap { * * @param listener the listener to notify */ - @UiThread public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) { cameraChangeDispatcher.setOnCameraMoveListener(listener); } @@ -1761,9 +1788,9 @@ public final class MapboxMap { * @param listener The callback that's invoked on every frame rendered to the map view. * To unset the callback, use null. */ - @UiThread public void setOnFpsChangedListener(@Nullable OnFpsChangedListener listener) { onFpsChangedListener = listener; + nativeMapView.setOnFpsChangedListener(listener); } // used by MapView @@ -1777,7 +1804,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the map is scrolled. * To unset the callback, use null. */ - @UiThread public void setOnScrollListener(@Nullable OnScrollListener listener) { onRegisterTouchListener.onRegisterScrollListener(listener); } @@ -1788,7 +1814,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the map is flinged. * To unset the callback, use null. */ - @UiThread public void setOnFlingListener(@Nullable OnFlingListener listener) { onRegisterTouchListener.onRegisterFlingListener(listener); } @@ -1799,7 +1824,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user clicks on the map view. * To unset the callback, use null. */ - @UiThread public void setOnMapClickListener(@Nullable OnMapClickListener listener) { onRegisterTouchListener.onRegisterMapClickListener(listener); } @@ -1810,7 +1834,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user long clicks on the map view. * To unset the callback, use null. */ - @UiThread public void setOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { onRegisterTouchListener.onRegisterMapLongClickListener(listener); } @@ -1821,7 +1844,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when the user clicks on an info window. * To unset the callback, use null. */ - @UiThread public void setOnInfoWindowClickListener(@Nullable OnInfoWindowClickListener listener) { annotationManager.getInfoWindowManager().setOnInfoWindowClickListener(listener); } @@ -1831,7 +1853,6 @@ public final class MapboxMap { * * @return Current active InfoWindow Click Listener */ - @UiThread public OnInfoWindowClickListener getOnInfoWindowClickListener() { return annotationManager.getInfoWindowManager().getOnInfoWindowClickListener(); } @@ -1842,7 +1863,6 @@ public final class MapboxMap { * @param listener The callback that's invoked when a marker's info window is long pressed. To unset the callback, * use null. */ - @UiThread public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) { annotationManager.getInfoWindowManager().setOnInfoWindowLongClickListener(listener); @@ -1871,7 +1891,6 @@ public final class MapboxMap { * * @return Current active InfoWindow Close Listener */ - @UiThread public OnInfoWindowCloseListener getOnInfoWindowCloseListener() { return annotationManager.getInfoWindowManager().getOnInfoWindowCloseListener(); } @@ -1884,8 +1903,10 @@ public final class MapboxMap { * Returns the status of the my-location layer. * * @return True if the my-location layer is enabled, false otherwise. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public boolean isMyLocationEnabled() { return trackingSettings.isMyLocationEnabled(); } @@ -1900,8 +1921,10 @@ public final class MapboxMap { * android.Manifest.permission#ACCESS_COARSE_LOCATION or android.Manifest.permission#ACCESS_FINE_LOCATION. * * @param enabled True to enable; false to disable. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public void setMyLocationEnabled(boolean enabled) { trackingSettings.setMyLocationEnabled(enabled); } @@ -1910,9 +1933,11 @@ public final class MapboxMap { * Returns the currently displayed user location, or null if there is no location data available. * * @return The currently displayed user location. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread @Nullable + @Deprecated public Location getMyLocation() { return trackingSettings.getMyLocation(); } @@ -1923,8 +1948,10 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the user clicks on a marker. * To unset the callback, use null. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { trackingSettings.setOnMyLocationChangeListener(listener); @@ -1934,8 +1961,10 @@ public final class MapboxMap { * Replaces the location source of the my-location layer. * * @param locationSource A {@link LocationEngine} location source to use in the my-location layer. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public void setLocationSource(@Nullable LocationEngine locationSource) { trackingSettings.setLocationSource(locationSource); } @@ -1945,8 +1974,10 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the location tracking mode changes. * To unset the callback, use null. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public void setOnMyLocationTrackingModeChangeListener( @Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { trackingSettings.setOnMyLocationTrackingModeChangeListener(listener); @@ -1957,8 +1988,10 @@ public final class MapboxMap { * * @param listener The callback that's invoked when the bearing tracking mode changes. * To unset the callback, use null. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ - @UiThread + @Deprecated public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) { trackingSettings.setOnMyBearingTrackingModeChangeListener(listener); } @@ -1972,7 +2005,6 @@ public final class MapboxMap { * * @param callback Callback method invoked when the snapshot is taken. */ - @UiThread public void snapshot(@NonNull SnapshotReadyCallback callback) { nativeMapView.addSnapshotCallback(callback); } @@ -1984,7 +2016,6 @@ public final class MapboxMap { * @param layerIds optionally - only query these layers * @return the list of feature */ - @UiThread @NonNull public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... layerIds) { @@ -1999,7 +2030,6 @@ public final class MapboxMap { * @param layerIds optionally - only query these layers * @return the list of feature */ - @UiThread @NonNull public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable Filter.Statement filter, @@ -2014,7 +2044,6 @@ public final class MapboxMap { * @param layerIds optionally - only query these layers * @return the list of feature */ - @UiThread @NonNull public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String... layerIds) { @@ -2029,7 +2058,6 @@ public final class MapboxMap { * @param layerIds optionally - only query these layers * @return the list of feature */ - @UiThread @NonNull public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates, @Nullable Filter.Statement filter, @@ -2037,6 +2065,15 @@ public final class MapboxMap { return nativeMapView.queryRenderedFeatures(coordinates, layerIds, filter); } + FocalPointChangeListener createFocalPointChangeListener() { + return new FocalPointChangeListener() { + @Override + public void onFocalPointChanged(PointF pointF) { + focalPoint = pointF; + } + }; + } + // // Interfaces // @@ -2135,6 +2172,21 @@ public final class MapboxMap { } /** + * Interface definition for a callback to be invoked for when the compass is animating. + */ + public interface OnCompassAnimationListener { + /** + * Called repeatedly as the compass continues to move after clicking on it. + */ + void onCompassAnimation(); + + /** + * Called when compass animation has ended. + */ + void onCompassAnimationFinished(); + } + + /** * Interface definition for a callback to be invoked when a frame is rendered to the map view. * * @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener) @@ -2299,7 +2351,10 @@ public final class MapboxMap { * Interface definition for a callback to be invoked when an MarkerView will be shown. * * @param <U> the instance type of MarkerView + * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android + * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java */ + @Deprecated public abstract static class MarkerViewAdapter<U extends MarkerView> { private Context context; 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 94e2fbcf3b..7b979f5563 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 @@ -85,9 +85,6 @@ public class MapboxMapOptions implements Parcelable { private String apiBaseUrl; - @Deprecated - private boolean textureMode; - private String style; /** @@ -155,7 +152,7 @@ public class MapboxMapOptions implements Parcelable { style = in.readString(); apiBaseUrl = in.readString(); - textureMode = in.readByte() != 0; + prefetchesTiles = in.readByte() != 0; zMediaOverlay = in.readByte() != 0; } @@ -299,8 +296,6 @@ public class MapboxMapOptions implements Parcelable { ColorUtils.getPrimaryColor(context))); mapboxMapOptions.myLocationAccuracyThreshold( typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyThreshold, 0)); - mapboxMapOptions.textureMode( - typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureMode, false)); mapboxMapOptions.setPrefetchesTiles( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); mapboxMapOptions.renderSurfaceOnTop( @@ -704,22 +699,6 @@ public class MapboxMapOptions implements Parcelable { } /** - * Enable TextureView as rendered surface. - * <p> - * Since the 4.2.0 release we replaced our TextureView with an SurfaceView implemenation. - * Enabling this option will use the deprecated TextureView instead. - * </p> - * - * @param textureMode True to enable texture mode - * @return This - * @deprecated As of the 4.2.0 release, using TextureView is deprecated. - */ - public MapboxMapOptions textureMode(boolean textureMode) { - this.textureMode = textureMode; - return this; - } - - /** * Enable tile pre-fetching. Loads tiles at a lower zoom-level to pre-render * a low resolution preview while more detailed tiles are loaded. * Enabled by default @@ -1070,16 +1049,6 @@ public class MapboxMapOptions implements Parcelable { return debugActive; } - /** - * Returns true if TextureView is being used a render view. - * - * @return True if TextureView is used. - * @deprecated As of the 4.2.0 release, using TextureView is deprecated. - */ - public boolean getTextureMode() { - return textureMode; - } - public static final Parcelable.Creator<MapboxMapOptions> CREATOR = new Parcelable.Creator<MapboxMapOptions>() { public MapboxMapOptions createFromParcel(Parcel in) { return new MapboxMapOptions(in); @@ -1143,7 +1112,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeString(style); dest.writeString(apiBaseUrl); - dest.writeByte((byte) (textureMode ? 1 : 0)); + dest.writeByte((byte) (prefetchesTiles ? 1 : 0)); dest.writeByte((byte) (zMediaOverlay ? 1 : 0)); } @@ -1320,7 +1289,6 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (myLocationAccuracyThreshold != +0.0f ? Float.floatToIntBits(myLocationAccuracyThreshold) : 0); result = 31 * result + (apiBaseUrl != null ? apiBaseUrl.hashCode() : 0); - result = 31 * result + (textureMode ? 1 : 0); result = 31 * result + (style != null ? style.hashCode() : 0); result = 31 * result + (prefetchesTiles ? 1 : 0); result = 31 * result + (zMediaOverlay ? 1 : 0); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java index b6bee199a3..072382ce07 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java @@ -53,7 +53,7 @@ class MarkerContainer implements Markers { mapboxMap) { int count = markerOptionsList.size(); List<Marker> markers = new ArrayList<>(count); - if (count > 0) { + if (nativeMapView != null && count > 0) { BaseMarkerOptions markerOptions; Marker marker; for (int i = 0; i < count; i++) { @@ -63,26 +63,13 @@ class MarkerContainer implements Markers { } if (markers.size() > 0) { - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addMarkers(markers); + long[] ids = nativeMapView.addMarkers(markers); + for (int i = 0; i < ids.length; i++) { + Marker createdMarker = markers.get(i); + createdMarker.setMapboxMap(mapboxMap); + createdMarker.setId(ids[i]); + annotations.put(ids[i], createdMarker); } - - long id = 0; - Marker m; - for (int i = 0; i < markers.size(); i++) { - m = markers.get(i); - m.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - // unit test - id++; - } - m.setId(id); - annotations.put(id, m); - } - } } return markers; 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 52596358e2..bd8a54783e 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 @@ -9,7 +9,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.DisplayMetrics; -import android.view.Surface; import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.annotations.Icon; @@ -17,10 +16,10 @@ import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.Filter; @@ -30,6 +29,7 @@ import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.utils.BitmapUtils; import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.Geometry; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -53,6 +53,9 @@ final class NativeMapView { //Hold a reference to prevent it from being GC'd as long as it's used on the native side private final FileSource fileSource; + // Used to schedule work on the MapRenderer Thread + private MapRenderer mapRenderer; + // Device density private final float pixelRatio; @@ -67,15 +70,15 @@ final class NativeMapView { // Constructors // - public NativeMapView(MapView mapView) { + public NativeMapView(final MapView mapView, MapRenderer mapRenderer) { + this.mapRenderer = mapRenderer; + this.mapView = mapView; + Context context = mapView.getContext(); fileSource = FileSource.getInstance(context); - pixelRatio = context.getResources().getDisplayMetrics().density; - this.mapView = mapView; - String programCacheDir = context.getCacheDir().getAbsolutePath(); - nativeInitialize(this, fileSource, pixelRatio, programCacheDir); + nativeInitialize(this, fileSource, mapRenderer, pixelRatio); } // @@ -84,9 +87,10 @@ final class NativeMapView { private boolean isDestroyedOn(String callingMethod) { if (destroyed && !TextUtils.isEmpty(callingMethod)) { - Timber.e(String.format(MapboxConstants.MAPBOX_LOCALE, + Timber.e( "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?", - callingMethod)); + callingMethod + ); } return destroyed; } @@ -97,32 +101,12 @@ final class NativeMapView { destroyed = true; } - public void createSurface(Surface surface) { - if (isDestroyedOn("createSurface")) { - return; - } - nativeCreateSurface(surface); - } - - public void destroySurface() { - if (isDestroyedOn("destroySurface")) { - return; - } - nativeDestroySurface(); - } - public void update() { if (isDestroyedOn("update")) { return; } - nativeUpdate(); - } - public void render() { - if (isDestroyedOn("render")) { - return; - } - nativeRender(); + mapRenderer.requestRender(); } public void resizeView(int width, int height) { @@ -143,41 +127,18 @@ final class NativeMapView { if (width > 65535) { // we have seen edge cases where devices return incorrect values #6111 Timber.e("Device returned an out of range width size, " - + "capping value at 65535 instead of " + width); + + "capping value at 65535 instead of %s", width); width = 65535; } if (height > 65535) { // we have seen edge cases where devices return incorrect values #6111 Timber.e("Device returned an out of range height size, " - + "capping value at 65535 instead of " + height); + + "capping value at 65535 instead of %s", height); height = 65535; } - nativeResizeView(width, height); - } - public void resizeFramebuffer(int fbWidth, int fbHeight) { - if (isDestroyedOn("resizeFramebuffer")) { - return; - } - if (fbWidth < 0) { - throw new IllegalArgumentException("fbWidth cannot be negative."); - } - - if (fbHeight < 0) { - throw new IllegalArgumentException("fbHeight cannot be negative."); - } - - if (fbWidth > 65535) { - throw new IllegalArgumentException( - "fbWidth cannot be greater than 65535."); - } - - if (fbHeight > 65535) { - throw new IllegalArgumentException( - "fbHeight cannot be greater than 65535."); - } - nativeResizeFramebuffer(fbWidth, fbHeight); + nativeResizeView(width, height); } public void setStyleUrl(String url) { @@ -272,6 +233,13 @@ final class NativeMapView { return nativeGetCameraForLatLngBounds(latLngBounds); } + public CameraPosition getCameraForGeometry(Geometry geometry, double bearing) { + if (isDestroyedOn("getCameraForGeometry")) { + return null; + } + return nativeGetCameraForGeometry(geometry, bearing); + } + public void resetPosition() { if (isDestroyedOn("resetPosition")) { return; @@ -507,6 +475,13 @@ final class NativeMapView { nativeAddAnnotationIcon(symbol, width, height, scale, pixels); } + public void removeAnnotationIcon(String symbol) { + if (isDestroyedOn("removeAnnotationIcon")) { + return; + } + nativeRemoveAnnotationIcon(symbol); + } + public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) { if (isDestroyedOn("setVisibleCoordinateBounds")) { return; @@ -542,13 +517,6 @@ final class NativeMapView { return nativeGetDebug(); } - public void setEnableFps(boolean enable) { - if (isDestroyedOn("setEnableFps")) { - return; - } - nativeSetEnableFps(enable); - } - public boolean isFullyLoaded() { if (isDestroyedOn("isFullyLoaded")) { return false; @@ -801,6 +769,13 @@ final class NativeMapView { nativeRemoveImage(name); } + public Bitmap getImage(String name) { + if (isDestroyedOn("getImage")) { + return null; + } + return nativeGetImage(name); + } + // Feature querying @NonNull @@ -832,13 +807,6 @@ final class NativeMapView { return features != null ? Arrays.asList(features) : new ArrayList<Feature>(); } - public void scheduleTakeSnapshot() { - if (isDestroyedOn("scheduleTakeSnapshot")) { - return; - } - nativeTakeSnapshot(); - } - public void setApiBaseUrl(String baseUrl) { if (isDestroyedOn("setApiBaseUrl")) { return; @@ -861,25 +829,12 @@ final class NativeMapView { // Callbacks // - protected void onInvalidate() { - if (mapView != null) { - mapView.onInvalidate(); - } - } - protected void onMapChanged(int rawChange) { if (mapView != null) { mapView.onMapChange(rawChange); } } - protected void onFpsChanged(double fps) { - if (isDestroyedOn("OnFpsChanged")) { - return; - } - mapView.onFpsChanged(fps); - } - protected void onSnapshotReady(Bitmap mapContent) { if (isDestroyedOn("OnSnapshotReady")) { return; @@ -897,31 +852,13 @@ final class NativeMapView { private native void nativeInitialize(NativeMapView nativeMapView, FileSource fileSource, - float pixelRatio, - String programCacheDir); + MapRenderer mapRenderer, + float pixelRatio); private native void nativeDestroy(); - private native void nativeInitializeDisplay(); - - private native void nativeTerminateDisplay(); - - private native void nativeInitializeContext(); - - private native void nativeTerminateContext(); - - private native void nativeCreateSurface(Object surface); - - private native void nativeDestroySurface(); - - private native void nativeUpdate(); - - private native void nativeRender(); - private native void nativeResizeView(int width, int height); - private native void nativeResizeFramebuffer(int fbWidth, int fbHeight); - private native void nativeSetStyleUrl(String url); private native String nativeGetStyleUrl(); @@ -944,6 +881,8 @@ final class NativeMapView { private native CameraPosition nativeGetCameraForLatLngBounds(LatLngBounds latLngBounds); + private native CameraPosition nativeGetCameraForGeometry(Geometry geometry, double bearing); + private native void nativeResetPosition(); private native double nativeGetPitch(); @@ -990,6 +929,8 @@ final class NativeMapView { private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels); + private native void nativeRemoveAnnotationIcon(String symbol); + private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration); @@ -1001,8 +942,6 @@ final class NativeMapView { private native boolean nativeGetDebug(); - private native void nativeSetEnableFps(boolean enable); - private native boolean nativeIsFullyLoaded(); private native void nativeSetReachability(boolean status); @@ -1069,6 +1008,8 @@ final class NativeMapView { private native void nativeRemoveImage(String name); + private native Bitmap nativeGetImage(String name); + private native void nativeUpdatePolygon(long polygonId, Polygon polygon); private native void nativeUpdatePolyline(long polylineId, Polyline polyline); @@ -1121,8 +1062,35 @@ final class NativeMapView { // void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { + if (isDestroyedOn("addSnapshotCallback")) { + return; + } snapshotReadyCallback = callback; - scheduleTakeSnapshot(); - render(); + nativeTakeSnapshot(); + } + + public void setOnFpsChangedListener(final MapboxMap.OnFpsChangedListener listener) { + mapRenderer.queueEvent(new Runnable() { + + @Override + public void run() { + mapRenderer.setOnFpsChangedListener(new MapboxMap.OnFpsChangedListener() { + + @Override + public void onFpsChanged(final double fps) { + mapView.post(new Runnable() { + + @Override + public void run() { + listener.onFpsChanged(fps); + } + + }); + } + + }); + } + + }); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java index e626fc3dc0..016862bddc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java @@ -42,7 +42,7 @@ class PolygonContainer implements Polygons { Polygon polygon; List<Polygon> polygons = new ArrayList<>(count); - if (count > 0) { + if (nativeMapView != null && count > 0) { for (PolygonOptions polygonOptions : polygonOptionsList) { polygon = polygonOptions.getPolygon(); if (!polygon.getPoints().isEmpty()) { @@ -50,23 +50,12 @@ class PolygonContainer implements Polygons { } } - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addPolygons(polygons); - } - - long id = 0; - for (int i = 0; i < polygons.size(); i++) { + long[] ids = nativeMapView.addPolygons(polygons); + for (int i = 0; i < ids.length; i++) { polygon = polygons.get(i); polygon.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - // unit test - id++; - } - polygon.setId(id); - annotations.put(id, polygon); + polygon.setId(ids[i]); + annotations.put(ids[i], polygon); } } return polygons; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java index b9a358c0f9..303b25fb55 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java @@ -41,8 +41,7 @@ class PolylineContainer implements Polylines { int count = polylineOptionsList.size(); Polyline polyline; List<Polyline> polylines = new ArrayList<>(count); - - if (count > 0) { + if (nativeMapView != null && count > 0) { for (PolylineOptions options : polylineOptionsList) { polyline = options.getPolyline(); if (!polyline.getPoints().isEmpty()) { @@ -50,25 +49,12 @@ class PolylineContainer implements Polylines { } } - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addPolylines(polylines); - } - - long id = 0; - Polyline p; - - for (int i = 0; i < polylines.size(); i++) { - p = polylines.get(i); - p.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - // unit test - id++; - } - p.setId(id); - annotations.put(id, p); + long[] ids = nativeMapView.addPolylines(polylines); + for (int i = 0; i < ids.length; i++) { + Polyline polylineCreated = polylines.get(i); + polylineCreated.setMapboxMap(mapboxMap); + polylineCreated.setId(ids[i]); + annotations.put(ids[i], polylineCreated); } } return polylines; 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 e0a634521b..16c73b1ca5 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 @@ -6,6 +6,7 @@ import android.support.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.geometry.ProjectedMeters; import com.mapbox.mapboxsdk.geometry.VisibleRegion; /** @@ -45,6 +46,20 @@ public class Projection { } /** + * Returns the spherical Mercator projected meters for a LatLng. + */ + public ProjectedMeters getProjectedMetersForLatLng(LatLng latLng) { + return nativeMapView.projectedMetersForLatLng(latLng); + } + + /** + * Returns the LatLng for a spherical Mercator projected meters. + */ + public LatLng getLatLngForProjectedMeters(ProjectedMeters projectedMeters) { + return nativeMapView.latLngForProjectedMeters(projectedMeters); + } + + /** * <p> * Returns the distance spanned by one pixel at the specified latitude and current zoom level. * </p> @@ -78,8 +93,6 @@ public class Projection { * @return The projection of the viewing frustum in its current state. */ public VisibleRegion getVisibleRegion() { - LatLngBounds.Builder builder = new LatLngBounds.Builder(); - float left = 0; float right = nativeMapView.getWidth(); float top = 0; @@ -90,12 +103,13 @@ public class Projection { LatLng bottomRight = fromScreenLocation(new PointF(right, bottom)); LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom)); - builder.include(topLeft) - .include(topRight) - .include(bottomRight) - .include(bottomLeft); - - return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, builder.build()); + return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, + LatLngBounds.from( + topRight.getLatitude(), + topRight.getLongitude(), + bottomLeft.getLatitude(), + bottomLeft.getLongitude()) + ); } /** 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 bd0bf7c83b..6881ca067b 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 @@ -20,7 +20,11 @@ import timber.log.Timber; /** * Settings for the user location and bearing tracking of a MapboxMap. + * + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ +@Deprecated public final class TrackingSettings { private final MyLocationView myLocationView; 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 d788b7772b..6f63c2eba8 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 @@ -346,7 +346,7 @@ final class Transform implements MapView.OnMapChangedListener { void setMinZoom(double minZoom) { if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) { - Timber.e("Not setting minZoomPreference, value is in unsupported range: " + minZoom); + Timber.e("Not setting minZoomPreference, value is in unsupported range: %s", minZoom); return; } mapView.setMinZoom(minZoom); @@ -358,7 +358,7 @@ final class Transform implements MapView.OnMapChangedListener { void setMaxZoom(double maxZoom) { if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) { - Timber.e("Not setting maxZoomPreference, value is in unsupported range: " + maxZoom); + Timber.e("Not setting maxZoomPreference, value is in unsupported range: %s", maxZoom); return; } mapView.setMaxZoom(maxZoom); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java new file mode 100644 index 0000000000..3f43522e01 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -0,0 +1,145 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +import android.content.Context; +import android.opengl.GLSurfaceView; + +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.storage.FileSource; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +/** + * The {@link MapRenderer} encapsulates the GL thread. + * <p> + * Performs actions on the GL thread to manage the GL resources and + * render on the one end and acts as a scheduler to request work to + * be performed on the GL thread on the other. + */ +public class MapRenderer implements GLSurfaceView.Renderer, MapRendererScheduler { + + // Holds the pointer to the native peer after initialisation + private long nativePtr = 0; + + private final GLSurfaceView glSurfaceView; + + private MapboxMap.OnFpsChangedListener onFpsChangedListener; + + public MapRenderer(Context context, GLSurfaceView glSurfaceView) { + this.glSurfaceView = glSurfaceView; + + FileSource fileSource = FileSource.getInstance(context); + float pixelRatio = context.getResources().getDisplayMetrics().density; + String programCacheDir = context.getCacheDir().getAbsolutePath(); + + // Initialise native peer + nativeInitialize(this, fileSource, pixelRatio, programCacheDir); + } + + public void setOnFpsChangedListener(MapboxMap.OnFpsChangedListener listener) { + onFpsChangedListener = listener; + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + nativeOnSurfaceCreated(); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + if (width < 0) { + throw new IllegalArgumentException("fbWidth cannot be negative."); + } + + if (height < 0) { + throw new IllegalArgumentException("fbHeight cannot be negative."); + } + + if (width > 65535) { + throw new IllegalArgumentException( + "fbWidth cannot be greater than 65535."); + } + + if (height > 65535) { + throw new IllegalArgumentException( + "fbHeight cannot be greater than 65535."); + } + + gl.glViewport(0, 0, width, height); + nativeOnSurfaceChanged(width, height); + } + + @Override + public void onDrawFrame(GL10 gl) { + nativeRender(); + + if (onFpsChangedListener != null) { + updateFps(); + } + } + + /** + * May be called from any thread. + * <p> + * Called from the renderer frontend to schedule a render. + */ + @Override + public void requestRender() { + glSurfaceView.requestRender(); + } + + /** + * May be called from any thread. + * <p> + * Schedules work to be performed on the MapRenderer thread. + * + * @param runnable the runnable to execute + */ + @Override + public void queueEvent(Runnable runnable) { + glSurfaceView.queueEvent(runnable); + } + + /** + * May be called from any thread. + * <p> + * Called from the native peer to schedule work on the GL + * thread. Explicit override for easier to read jni code. + * + * @param runnable the runnable to execute + * @see MapRendererRunnable + */ + void queueEvent(MapRendererRunnable runnable) { + this.queueEvent((Runnable) runnable); + } + + private native void nativeInitialize(MapRenderer self, + FileSource fileSource, + float pixelRatio, + String programCacheDir); + + @Override + protected native void finalize() throws Throwable; + + private native void nativeOnSurfaceCreated(); + + private native void nativeOnSurfaceChanged(int width, int height); + + private native void nativeRender(); + + private long frames; + private long timeElapsed; + + private void updateFps() { + frames++; + long currentTime = System.nanoTime(); + double fps = 0; + if (currentTime - timeElapsed >= 1) { + fps = frames / ((currentTime - timeElapsed) / 1E9); + onFpsChangedListener.onFpsChanged(fps); + timeElapsed = currentTime; + frames = 0; + } + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java new file mode 100644 index 0000000000..28246fe578 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java @@ -0,0 +1,29 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +/** + * Peer class for {@link Runnable}s to be scheduled on the {@link MapRenderer} thread. + * The actual work is performed in the native peer. + */ +class MapRendererRunnable implements Runnable { + + // Holds the pointer to the native peer after initialisation + private final long nativePtr; + + /** + * Constructed from the native peer constructor + * + * @param nativePtr the native peer's memory address + */ + MapRendererRunnable(long nativePtr) { + this.nativePtr = nativePtr; + } + + @Override + public native void run(); + + @Override + protected native void finalize() throws Throwable; + + private native void nativeInitialize(); + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java new file mode 100644 index 0000000000..7ad4f124d8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.maps.renderer; + +/** + * Can be used to schedule work on the map renderer + * thread or request a render. + */ +public interface MapRendererScheduler { + + void requestRender(); + + void queueEvent(Runnable runnable); + +} 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 2b327409ae..45f72af1c5 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,10 +1,8 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.content.Context; -import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; @@ -13,11 +11,8 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; -import com.mapbox.mapboxsdk.maps.FocalPointChangeListener; import com.mapbox.mapboxsdk.maps.MapboxMap; -import java.lang.ref.WeakReference; - /** * UI element overlaid on a map to show the map's bearing when it isn't true north (0.0). Tapping * the compass resets the bearing to true north and hides the compass. @@ -27,16 +22,17 @@ import java.lang.ref.WeakReference; * use {@link com.mapbox.mapboxsdk.maps.UiSettings}. * </p> */ -public final class CompassView extends AppCompatImageView implements Runnable, FocalPointChangeListener { +public final class CompassView extends AppCompatImageView implements Runnable { - private static final long TIME_WAIT_IDLE = 500; + public static final long TIME_WAIT_IDLE = 500; + public static final long TIME_MAP_NORTH_ANIMATION = 150; private static final long TIME_FADE_ANIMATION = TIME_WAIT_IDLE; - private static final long TIME_MAP_NORTH_ANIMATION = 150; private float rotation = 0.0f; private boolean fadeCompassViewFacingNorth = true; private ViewPropertyAnimatorCompat fadeAnimator; - private PointF focalPoint; + private MapboxMap.OnCompassAnimationListener compassAnimationListener; + private boolean isAnimating = false; public CompassView(Context context) { super(context); @@ -62,9 +58,12 @@ public final class CompassView extends AppCompatImageView implements Runnable, F setLayoutParams(lp); } - // TODO refactor MapboxMap and replace with interface - public void setMapboxMap(@NonNull MapboxMap mapboxMap) { - setOnClickListener(new CompassClickListener(mapboxMap, this)); + public void injectCompassAnimationListener(@NonNull MapboxMap.OnCompassAnimationListener compassAnimationListener) { + this.compassAnimationListener = compassAnimationListener; + } + + public void isAnimating(boolean isAnimating) { + this.isAnimating = isAnimating; } private void resetAnimation() { @@ -97,11 +96,6 @@ public final class CompassView extends AppCompatImageView implements Runnable, F } } - @Nullable - PointF getFocalPoint() { - return focalPoint; - } - /** * Updates the direction of the compass. * @@ -126,6 +120,7 @@ public final class CompassView extends AppCompatImageView implements Runnable, F setVisibility(View.VISIBLE); } + notifyCompassAnimationListenerWhenAnimating(); setRotation(rotation); } @@ -157,7 +152,8 @@ public final class CompassView extends AppCompatImageView implements Runnable, F @Override public void run() { - if (isFacingNorth() && fadeCompassViewFacingNorth) { + if (isHidden()) { + compassAnimationListener.onCompassAnimationFinished(); resetAnimation(); setLayerType(View.LAYER_TYPE_HARDWARE, null); fadeAnimator = ViewCompat.animate(CompassView.this).alpha(0.0f).setDuration(TIME_FADE_ANIMATION); @@ -172,34 +168,9 @@ public final class CompassView extends AppCompatImageView implements Runnable, F } } - @Override - public void onFocalPointChanged(PointF pointF) { - focalPoint = pointF; - } - - static class CompassClickListener implements View.OnClickListener { - - private WeakReference<MapboxMap> mapboxMap; - private WeakReference<CompassView> compassView; - - CompassClickListener(final MapboxMap mapboxMap, CompassView compassView) { - this.mapboxMap = new WeakReference<>(mapboxMap); - this.compassView = new WeakReference<>(compassView); - } - - @Override - public void onClick(View view) { - final MapboxMap mapboxMap = this.mapboxMap.get(); - final CompassView compassView = this.compassView.get(); - if (mapboxMap != null && compassView != null) { - 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); - } + private void notifyCompassAnimationListenerWhenAnimating() { + if (isAnimating) { + compassAnimationListener.onCompassAnimation(); } } } 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 017fdb353a..983ba2550f 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 @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Camera; import android.graphics.Canvas; @@ -48,7 +49,10 @@ import timber.log.Timber; * <p> * Use {@link MyLocationViewSettings} to manipulate the state of this view. * </p> + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ +@Deprecated public class MyLocationView extends View { private static final int UNDEFINED_TINT_COLOR = -1; @@ -76,7 +80,7 @@ public class MyLocationView extends View { private ValueAnimator locationChangeAnimator; private ValueAnimator accuracyAnimator; private ValueAnimator directionAnimator; - private boolean locationChangeAnimationEnabled; + private boolean locationChangeAnimationEnabled = true; private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @@ -775,6 +779,7 @@ public class MyLocationView extends View { locationSource = new WeakReference<>(locationEngine); } + @SuppressLint("MissingPermission") @Override public void onConnected() { MyLocationView locationView = userLocationView.get(); @@ -808,6 +813,9 @@ public class MyLocationView extends View { private Sensor rotationVectorSensor; private float[] matrix = new float[9]; + private float[] rotationVectorValue; + private float[] truncatedRotationVectorValue = new float[4]; + private float[] orientation = new float[3]; private boolean reportMissingSensor = true; // Compass data @@ -844,9 +852,8 @@ public class MyLocationView extends View { } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { - - // calculate the rotation matrix - SensorManager.getRotationMatrixFromVector(matrix, event.values); + rotationVectorValue = getRotationVectorFromSensorEvent(event); + SensorManager.getRotationMatrixFromVector(matrix, rotationVectorValue); SensorManager.getOrientation(matrix, orientation); magneticHeading = (float) Math.toDegrees(SensorManager.getOrientation(matrix, orientation)[0]); @@ -863,6 +870,28 @@ public class MyLocationView extends View { } } + /** + * Pulls out the rotation vector from a SensorEvent, with a maximum length + * vector of four elements to avoid potential compatibility issues. + * + * @param event the sensor event + * @return the events rotation vector, potentially truncated + */ + @NonNull + float[] getRotationVectorFromSensorEvent(@NonNull SensorEvent event) { + if (event.values.length > 4) { + // On some Samsung devices SensorManager.getRotationMatrixFromVector + // appears to throw an exception if rotation vector has length > 4. + // For the purposes of this class the first 4 values of the + // rotation vector are sufficient (see crbug.com/335298 for details). + // Only affects Android 4.3 + System.arraycopy(event.values, 0, truncatedRotationVectorValue, 0, 4); + return truncatedRotationVectorValue; + } else { + return event.values; + } + } + private void rotateCamera(float rotation) { CameraPosition.Builder builder = new CameraPosition.Builder(); builder.bearing(rotation); 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 ea74bc57aa..a1d5b13b8b 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 @@ -13,7 +13,10 @@ import com.mapbox.mapboxsdk.maps.Projection; /** * Settings to configure the visual appearance of the MyLocationView. + * @deprecated use location layer plugin from + * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead. */ +@Deprecated public class MyLocationViewSettings { private Projection projection; |