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 4b26be558..9e08d93bf 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 @@ -30,7 +30,7 @@ import java.util.List; * Exposes convenience methods to add/remove/update all subtypes of annotations found in com.mapbox.mapboxsdk.annotations. *

*/ -class AnnotationManager { +class AnnotationManager implements MapView.OnMapChangedListener { private NativeMapView nativeMapView; private IconManager iconManager; @@ -41,6 +41,7 @@ class AnnotationManager { private List selectedMarkers; private MapboxMap.OnMarkerClickListener onMarkerClickListener; + private boolean isWaitingForRenderInvoke; AnnotationManager(NativeMapView view, IconManager iconManager, InfoWindowManager manager) { this.nativeMapView = view; @@ -48,6 +49,19 @@ class AnnotationManager { this.infoWindowManager = manager; this.selectedMarkers = new ArrayList<>(); this.annotations = new LongSparseArray<>(); + + if (view != null) { + // null checking needed for unit tests + view.addOnMapChangedListener(this); + } + } + + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (isWaitingForRenderInvoke && change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) { + isWaitingForRenderInvoke = false; + markerViewManager.invalidateViewMarkersInVisibleRegion(); + } } // @@ -194,18 +208,24 @@ class AnnotationManager { } MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap) { + isWaitingForRenderInvoke = true; MarkerView marker = prepareViewMarker(markerOptions); marker.setMapboxMap(mapboxMap); long id = nativeMapView.addMarker(marker); marker.setId(id); annotations.put(id, marker); - markerViewManager.invalidateViewMarkersInVisibleRegion(); return marker; } List addMarkerViews(@NonNull List markerViewOptions, @NonNull MapboxMap mapboxMap) { List markers = new ArrayList<>(); for (BaseMarkerViewOptions markerViewOption : markerViewOptions) { + // if last marker + if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) { + // get notified when render occurs to invalidate and draw MarkerViews + isWaitingForRenderInvoke = true; + } + // add marker to map MarkerView marker = prepareViewMarker(markerViewOption); marker.setMapboxMap(mapboxMap); long id = nativeMapView.addMarker(marker); @@ -283,7 +303,7 @@ class AnnotationManager { } if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) { - infoWindowManager.getInfoWindows().add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView())); + infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView())); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java index 7b5880797..791f310b4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java @@ -80,4 +80,8 @@ class InfoWindowManager { MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() { return onInfoWindowCloseListener; } + + public void add(InfoWindow infoWindow) { + infoWindows.add(infoWindow); + } } 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 a9f2ed23f..5840e574c 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 @@ -87,7 +87,6 @@ import java.util.Collections; import java.util.Hashtable; import java.util.Iterator; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing; @@ -126,7 +125,6 @@ public class MapView extends FrameLayout { private Projection projection; - private CopyOnWriteArrayList onMapChangedListener; private ZoomButtonsController zoomButtonsController; private ConnectivityReceiver connectivityReceiver; private float screenDensity = 1.0f; @@ -153,7 +151,6 @@ public class MapView extends FrameLayout { private boolean styleWasSet = false; private List onMapReadyCallbackList; - private MapboxMap.CancelableCallback cameraCancelableCallback; private SnapshotRequest snapshotRequest; private boolean onStartCalled; @@ -192,7 +189,6 @@ public class MapView extends FrameLayout { initialLoad = true; onMapReadyCallbackList = new ArrayList<>(); - onMapChangedListener = new CopyOnWriteArrayList<>(); View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this); setWillNotDraw(false); @@ -483,7 +479,7 @@ public class MapView extends FrameLayout { } // invalidate camera to update overlain views with correct tilt value - invalidateCameraPosition(); + mapboxMap.invalidateCameraPosition(); } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) { mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation(); @@ -705,11 +701,11 @@ public class MapView extends FrameLayout { // Center coordinate // - LatLng getCenterCoordinate(){ + LatLng getCenterCoordinate() { return nativeMapView.getLatLng(); } - void setCenterCoordinate(LatLng centerCoordinate){ + void setCenterCoordinate(LatLng centerCoordinate) { nativeMapView.setLatLng(centerCoordinate); } @@ -737,7 +733,7 @@ public class MapView extends FrameLayout { return; } long duration = animated ? MapboxConstants.ANIMATION_DURATION : 0; - cancelTransitions(); + mapboxMap.cancelTransitions(); // Out of range directions are normalised in setBearing nativeMapView.setBearing(-direction, duration); } @@ -747,7 +743,7 @@ public class MapView extends FrameLayout { return; } myLocationView.setBearing(0); - cancelTransitions(); + mapboxMap.cancelTransitions(); nativeMapView.resetNorth(); } @@ -817,16 +813,13 @@ public class MapView extends FrameLayout { private void zoom(boolean zoomIn, float x, float y) { // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); if (zoomIn) { nativeMapView.scaleBy(2.0, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION); } else { nativeMapView.scaleBy(0.5, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION); } - - // work around to invalidate camera position - postDelayed(new ZoomInvalidator(mapboxMap), MapboxConstants.ANIMATION_DURATION); } // @@ -1067,76 +1060,6 @@ public class MapView extends FrameLayout { return nativeMapView.getMetersPerPixelAtLatitude(latitude, getZoom()) / screenDensity; } - // - // Mapbox Core GL Camera - // - - private void cancelTransitions(){ - if (cameraCancelableCallback != null) { - cameraCancelableCallback.onCancel(); - cameraCancelableCallback = null; - } - nativeMapView.cancelTransitions(); - } - - void jumpTo(double bearing, LatLng center, double pitch, double zoom) { - if (destroyed) { - return; - } - cancelTransitions(); - nativeMapView.jumpTo(bearing, center, pitch, zoom); - } - - void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback cancelableCallback) { - if (destroyed) { - return; - } - cancelTransitions(); - - // Register callbacks early enough - if (cancelableCallback != null) { - cameraCancelableCallback = cancelableCallback; - addOnMapChangedListener(new OnMapChangedListener() { - @Override - public void onMapChanged(@MapChange int change) { - if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) { - cameraCancelableCallback.onFinish(); - cameraCancelableCallback = null; - // Clean up after self - removeOnMapChangedListener(this); - } - } - }); - } - - nativeMapView.easeTo(bearing, center, duration, pitch, zoom, easingInterpolator); - } - - void flyTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) { - if (destroyed) { - return; - } - cancelTransitions(); - - // Register callbacks early enough - if (cancelableCallback != null) { - cameraCancelableCallback = cancelableCallback; - addOnMapChangedListener(new OnMapChangedListener() { - @Override - public void onMapChanged(@MapChange int change) { - if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) { - cancelableCallback.onFinish(); - cameraCancelableCallback = null; - // Clean up after self - removeOnMapChangedListener(this); - } - } - }); - } - - nativeMapView.flyTo(bearing, center, duration, pitch, zoom); - } - // // Rendering // @@ -1268,14 +1191,9 @@ public class MapView extends FrameLayout { } } - CameraPosition invalidateCameraPosition() { - if (destroyed) { - return new CameraPosition.Builder().build(); - } - CameraPosition position = new CameraPosition.Builder(nativeMapView.getCameraValues()).build(); + void updateCameraPosition(@NonNull CameraPosition position) { myLocationView.setCameraPosition(position); mapboxMap.getMarkerViewManager().setTilt((float) position.tilt); - return position; } double getBearing() { @@ -1560,7 +1478,7 @@ public class MapView extends FrameLayout { return false; } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); return true; } @@ -1649,12 +1567,12 @@ public class MapView extends FrameLayout { return false; } - resetTrackingModesIfRequired(true, false); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false); double decelerationRate = 1; // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); double offsetX = velocityX * decelerationRate / 4 / screenDensity; double offsetY = velocityY * decelerationRate / 4 / screenDensity; @@ -1689,9 +1607,9 @@ public class MapView extends FrameLayout { requestDisallowInterceptTouchEvent(true); // reset tracking if needed - resetTrackingModesIfRequired(true, false); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false); // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // Scroll the map nativeMapView.moveBy(-distanceX / screenDensity, -distanceY / screenDensity); @@ -1762,7 +1680,7 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // Gesture is a quickzoom if there aren't two fingers quickZoom = !twoTap; @@ -1771,7 +1689,7 @@ public class MapView extends FrameLayout { // to be in the center of the map. Therefore the zoom will translate the map center, so tracking // should be disabled. - resetTrackingModesIfRequired(!quickZoom, false); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(!quickZoom, false); // Scale the map if (focalPoint != null) { // arround user provided focal point @@ -1843,12 +1761,12 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // rotation constitutes translation of anything except the center of // rotation, so cancel both location and bearing tracking if required - resetTrackingModesIfRequired(true, true); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, true); // Get rotate value double bearing = nativeMapView.getBearing(); @@ -1919,7 +1837,7 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // Get tilt value (scale and clamp) double pitch = getTilt(); @@ -1986,7 +1904,7 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // Move left nativeMapView.moveBy(scrollDist / screenDensity, 0.0 / screenDensity); @@ -1998,8 +1916,8 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); - + mapboxMap.cancelTransitions(); + // Move right nativeMapView.moveBy(-scrollDist / screenDensity, 0.0 / screenDensity); return true; @@ -2010,8 +1928,8 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); - + mapboxMap.cancelTransitions(); + // Move up nativeMapView.moveBy(0.0 / screenDensity, scrollDist / screenDensity); return true; @@ -2022,7 +1940,7 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); + mapboxMap.cancelTransitions(); // Move down nativeMapView.moveBy(0.0 / screenDensity, -scrollDist / screenDensity); @@ -2102,8 +2020,8 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); - + mapboxMap.cancelTransitions(); + // Scroll the map nativeMapView.moveBy(-10.0 * event.getX() / screenDensity, -10.0 * event.getY() / screenDensity); return true; @@ -2198,8 +2116,8 @@ public class MapView extends FrameLayout { } // Cancel any animation - cancelTransitions(); - + mapboxMap.cancelTransitions(); + // Get the vertical scroll amount, one click = 1 float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); @@ -2289,7 +2207,7 @@ public class MapView extends FrameLayout { */ public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) { if (listener != null) { - onMapChangedListener.add(listener); + nativeMapView.addOnMapChangedListener(listener); } } @@ -2301,7 +2219,7 @@ public class MapView extends FrameLayout { */ public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) { if (listener != null) { - onMapChangedListener.remove(listener); + nativeMapView.removeOnMapChangedListener(listener); } } @@ -2309,14 +2227,7 @@ public class MapView extends FrameLayout { // Called via JNI from NativeMapView // Forward to any listeners protected void onMapChanged(int mapChange) { - if (onMapChangedListener != null) { - OnMapChangedListener listener; - final Iterator iterator = onMapChangedListener.iterator(); - while (iterator.hasNext()) { - listener = iterator.next(); - listener.onMapChanged(mapChange); - } - } + nativeMapView.onMapChangedEventDispatch(mapChange); } // @@ -2382,42 +2293,6 @@ public class MapView extends FrameLayout { ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } - void resetTrackingModesIfRequired(boolean translate, boolean rotate) { - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - - // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off - if (translate && !trackingSettings.isLocationTrackingDisabled() && trackingSettings.isDismissLocationTrackingOnGesture()) { - resetLocationTrackingMode(); - } - - // reset bearing tracking only on rotate - if (rotate && !trackingSettings.isBearingTrackingDisabled() && trackingSettings.isDismissBearingTrackingOnGesture()) { - resetBearingTrackingMode(); - } - } - - void resetTrackingModesIfRequired(CameraPosition cameraPosition) { - resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1); - } - - private void resetLocationTrackingMode() { - try { - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); - } catch (SecurityException ignore) { - // User did not accept location permissions - } - } - - private void resetBearingTrackingMode() { - try { - TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); - trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE); - } catch (SecurityException ignore) { - // User did not accept location permissions - } - } - // // Compass // @@ -2653,21 +2528,6 @@ public class MapView extends FrameLayout { } } - private static class ZoomInvalidator implements Runnable { - - private MapboxMap mapboxMap; - - ZoomInvalidator(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public void run() { - // invalidate camera position - mapboxMap.getCameraPosition(); - } - } - /** * Definition of a map change event. * 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 ab6476f6e..8e42e794b 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 @@ -5,7 +5,6 @@ import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.location.Location; -import android.os.SystemClock; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -45,7 +44,6 @@ import com.mapbox.services.commons.geojson.Feature; import java.lang.reflect.ParameterizedType; import java.util.List; -import java.util.concurrent.TimeUnit; /** * The general class to interact with in the Android Mapbox SDK. It exposes the entry point for all @@ -64,9 +62,7 @@ public class MapboxMap { private TrackingSettings trackingSettings; private MyLocationViewSettings myLocationViewSettings; private Projection projection; - private CameraPosition cameraPosition; - private boolean invalidCameraPosition; - + private Transform transform; private boolean myLocationEnabled; private MapboxMap.OnMapClickListener onMapClickListener; @@ -78,7 +74,6 @@ public class MapboxMap { private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; private MapboxMap.OnFpsChangedListener onFpsChangedListener; - private MapboxMap.OnCameraChangeListener onCameraChangeListener; private AnnotationManager annotationManager; private InfoWindowManager infoWindowManager; @@ -88,12 +83,18 @@ public class MapboxMap { MapboxMap(@NonNull MapView mapView, IconManager iconManager) { this.mapView = mapView; - this.mapView.addOnMapChangedListener(new MapChangeCameraPositionListener()); uiSettings = new UiSettings(mapView); trackingSettings = new TrackingSettings(this.mapView, uiSettings); projection = new Projection(mapView); infoWindowManager = new InfoWindowManager(); annotationManager = new AnnotationManager(mapView.getNativeMapView(), iconManager, infoWindowManager); + + // TODO inject NativeMapView https://github.com/mapbox/mapbox-gl-native/issues/4100 + NativeMapView nativeMapView = mapView.getNativeMapView(); + if (nativeMapView != null) { + transform = new Transform(nativeMapView, this); + nativeMapView.addOnMapChangedListener(new CameraInvalidator()); + } } // Style @@ -378,6 +379,16 @@ public class MapboxMap { // Camera API // + /** + * Cancels ongoing animations. + *

+ * This invokes the {@link CancelableCallback} for ongoing camera updates. + *

+ */ + public void cancelTransitions() { + transform.cancelTransitions(); + } + /** * Gets the current position of the camera. * The CameraPosition returned is a snapshot of the current position, and will not automatically update when the @@ -386,10 +397,7 @@ public class MapboxMap { * @return The current position of the Camera. */ public final CameraPosition getCameraPosition() { - if (invalidCameraPosition) { - invalidateCameraPosition(); - } - return cameraPosition; + return transform.getCameraPosition(); } /** @@ -400,7 +408,7 @@ public class MapboxMap { * @param cameraPosition the camera position to set */ public void setCameraPosition(@NonNull CameraPosition cameraPosition) { - moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); + moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), null); } /** @@ -424,17 +432,13 @@ public class MapboxMap { * @param callback the callback to be invoked when an animation finishes or is canceled */ @UiThread - public final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { - cameraPosition = update.getCameraPosition(this); - mapView.resetTrackingModesIfRequired(cameraPosition); - mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); - if (callback != null) { - callback.onFinish(); - } - - if (onCameraChangeListener != null) { - onCameraChangeListener.onCameraChange(this.cameraPosition); - } + public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) { + mapView.post(new Runnable() { + @Override + public void run() { + transform.moveCamera(update, callback); + } + }); } /** @@ -489,11 +493,44 @@ public class MapboxMap { easeCamera(update, durationMs, true, callback); } + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param easingInterpolator True for easing interpolator, false for linear. + */ @UiThread public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) { easeCamera(update, durationMs, easingInterpolator, null); } + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param easingInterpolator True for easing interpolator, false for linear. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + */ @UiThread public final void easeCamera( CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) { @@ -501,33 +538,34 @@ public class MapboxMap { easeCamera(update, durationMs, easingInterpolator, true, callback); } + /** + * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected + * unless specified within {@link CameraUpdate}. A callback can be used to be notified when + * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it + * will return the current location of the camera in flight. + *

+ * Note that this will cancel location tracking mode if enabled. + *

+ * + * @param update The change that should be applied to the camera. + * @param durationMs The duration of the animation in milliseconds. This must be strictly + * positive, otherwise an IllegalArgumentException will be thrown. + * @param resetTrackingMode True to reset tracking modes if required, false to ignore + * @param easingInterpolator True for easing interpolator, false for linear. + * @param callback An optional callback to be notified from the main thread when the animation + * stops. If the animation stops due to its natural completion, the callback + * will be notified with onFinish(). If the animation stops due to interruption + * by a later camera movement or a user gesture, onCancel() will be called. + * Do not update or ease the camera from within onCancel(). + */ @UiThread - public final void easeCamera( - CameraUpdate update, int durationMs, boolean easingInterpolator, boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { - // dismiss tracking, moving camera is equal to a gesture - cameraPosition = update.getCameraPosition(this); - if (resetTrackingMode) { - mapView.resetTrackingModesIfRequired(cameraPosition); - } - - mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, - cameraPosition.zoom, easingInterpolator, new CancelableCallback() { - @Override - public void onCancel() { - if (callback != null) { - callback.onCancel(); - } - invalidateCameraPosition(); - } - - @Override - public void onFinish() { - if (callback != null) { - callback.onFinish(); - } - invalidateCameraPosition(); - } - }); + public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, final boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { + mapView.post(new Runnable() { + @Override + public void run() { + transform.easeCamera(update, durationMs, easingInterpolator, resetTrackingMode, callback); + } + }); } /** @@ -596,58 +634,22 @@ public class MapboxMap { * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates. */ @UiThread - public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { - cameraPosition = update.getCameraPosition(this); - mapView.resetTrackingModesIfRequired(cameraPosition); - mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, - cameraPosition.zoom, new CancelableCallback() { - @Override - public void onCancel() { - if (callback != null) { - callback.onCancel(); - } - invalidateCameraPosition(); - } - - @Override - public void onFinish() { - if (onCameraChangeListener != null) { - onCameraChangeListener.onCameraChange(cameraPosition); - } - - if (callback != null) { - callback.onFinish(); - } - invalidateCameraPosition(); - } - }); - } - - /** - * Converts milliseconds to nanoseconds - * - * @param durationMs The time in milliseconds - * @return time in nanoseconds - */ - private long getDurationNano(long durationMs) { - return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0; + public final void animateCamera(final CameraUpdate update, final int durationMs, final MapboxMap.CancelableCallback callback) { + mapView.post(new Runnable() { + @Override + public void run() { + transform.animateCamera(update, durationMs, callback); + } + }); } /** * Invalidates the current camera position by reconstructing it from mbgl */ - private void invalidateCameraPosition() { - if (invalidCameraPosition) { - invalidCameraPosition = false; - - CameraPosition cameraPosition = mapView.invalidateCameraPosition(); - if (cameraPosition != null) { - this.cameraPosition = cameraPosition; - } - - if (onCameraChangeListener != null) { - onCameraChangeListener.onCameraChange(this.cameraPosition); - } + void invalidateCameraPosition() { + CameraPosition cameraPosition = transform.invalidateCameraPosition(); + if (cameraPosition != null) { + mapView.updateCameraPosition(cameraPosition); } } @@ -659,7 +661,7 @@ public class MapboxMap { * Resets the map view to face north. */ public void resetNorth() { - mapView.resetNorth(); + transform.resetNorth(); } // @@ -875,7 +877,8 @@ public class MapboxMap { @UiThread @NonNull - public List addMarkerViews(@NonNull List markerViewOptions) { + public List addMarkerViews(@NonNull List markerViewOptions) { return annotationManager.addMarkerViews(markerViewOptions, this); } @@ -897,7 +900,8 @@ public class MapboxMap { */ @UiThread @NonNull - public List addMarkers(@NonNull List markerOptionsList) { + public List addMarkers(@NonNull List markerOptionsList) { return annotationManager.addMarkers(markerOptionsList, this); } @@ -1239,7 +1243,7 @@ public class MapboxMap { return infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows(); } - // used by MapView + // Internal API List getInfoWindows() { return infoWindowManager.getInfoWindows(); } @@ -1248,6 +1252,11 @@ public class MapboxMap { return annotationManager; } + Transform getTransform() { + return transform; + } + + // // Padding // @@ -1299,7 +1308,7 @@ public class MapboxMap { */ @UiThread public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) { - onCameraChangeListener = listener; + transform.setOnCameraChangeListener(listener); } /** @@ -1410,7 +1419,8 @@ public class MapboxMap { * use null. */ @UiThread - public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) { + public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener + listener) { infoWindowManager.setOnInfoWindowLongClickListener(listener); } @@ -1493,7 +1503,8 @@ public class MapboxMap { * To unset the callback, use null. */ @UiThread - public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { + public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener + listener) { mapView.setOnMyLocationChangeListener(listener); } @@ -1504,12 +1515,14 @@ public class MapboxMap { * To unset the callback, use null. */ @UiThread - public void setOnMyLocationTrackingModeChangeListener(@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { + public void setOnMyLocationTrackingModeChangeListener + (@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { onMyLocationTrackingModeChangeListener = listener; } // used by MapView - MapboxMap.OnMyLocationTrackingModeChangeListener getOnMyLocationTrackingModeChangeListener() { + MapboxMap.OnMyLocationTrackingModeChangeListener getOnMyLocationTrackingModeChangeListener + () { return onMyLocationTrackingModeChangeListener; } @@ -1520,7 +1533,8 @@ public class MapboxMap { * To unset the callback, use null. */ @UiThread - public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) { + public void setOnMyBearingTrackingModeChangeListener + (@Nullable OnMyBearingTrackingModeChangeListener listener) { onMyBearingTrackingModeChangeListener = listener; } @@ -1582,7 +1596,8 @@ public class MapboxMap { */ @UiThread @NonNull - public List queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... layerIds) { + public List queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... + layerIds) { return mapView.getNativeMapView().queryRenderedFeatures(coordinates, layerIds); } @@ -1595,10 +1610,25 @@ public class MapboxMap { */ @UiThread @NonNull - public List queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String... layerIds) { + public List queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String... + layerIds) { return mapView.getNativeMapView().queryRenderedFeatures(coordinates, layerIds); } + // + // Innner classes + // + + private class CameraInvalidator implements MapView.OnMapChangedListener { + + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (change == MapView.REGION_DID_CHANGE_ANIMATED) { + invalidateCameraPosition(); + } + } + } + // // Interfaces // @@ -1963,23 +1993,4 @@ public class MapboxMap { */ void onSnapshotReady(Bitmap snapshot); } - - private class MapChangeCameraPositionListener implements MapView.OnMapChangedListener { - - private static final long UPDATE_RATE_MS = 400; - private long previousUpdateTimestamp = 0; - - @Override - public void onMapChanged(@MapView.MapChange int change) { - if (change >= MapView.REGION_WILL_CHANGE && change <= MapView.REGION_DID_CHANGE_ANIMATED) { - invalidCameraPosition = true; - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime < previousUpdateTimestamp) { - return; - } - invalidateCameraPosition(); - previousUpdateTimestamp = currentTime + UPDATE_RATE_MS; - } - } - } } 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 e7e3e647a..cdd275ee3 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 @@ -30,6 +30,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; // Class that wraps the native methods for convenience final class NativeMapView { @@ -44,6 +45,8 @@ final class NativeMapView { private final float pixelRatio; + private CopyOnWriteArrayList onMapChangedListeners; + // // Static methods // @@ -83,7 +86,7 @@ final class NativeMapView { if (totalMemory < 0) { throw new IllegalArgumentException("totalMemory cannot be negative."); } - + onMapChangedListeners = new CopyOnWriteArrayList<>(); this.mapView = mapView; nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory); } @@ -778,4 +781,24 @@ final class NativeMapView { private native Feature[] nativeQueryRenderedFeaturesForBox(long nativeMapViewPtr, float left, float top, float right, float bottom, String[] layerIds); private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl); + + // + // MapChangeEvents + // + + void addOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) { + onMapChangedListeners.add(listener); + } + + void removeOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) { + onMapChangedListeners.remove(listener); + } + + void onMapChangedEventDispatch(int mapChange) { + if (onMapChangedListeners != null) { + for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) { + onMapChangedListener.onMapChanged(mapChange); + } + } + } } 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 c32d4a890..7f655fbee 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 @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.maps; import android.support.annotation.NonNull; import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; @@ -211,4 +212,27 @@ public class TrackingSettings { return uiSettings.isScrollGesturesEnabled() && (dismissLocationTrackingOnGesture || myLocationTrackingMode == MyLocationTracking.TRACKING_NONE); } + + /** + * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed, + * bearing tracking if there is a rotation. + * + * @param translate + * @param rotate + */ + public void resetTrackingModesIfRequired(boolean translate, boolean rotate) { + // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off + if (translate && !isLocationTrackingDisabled() && isDismissLocationTrackingOnGesture()) { + setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE); + } + + // reset bearing tracking only on rotate + if (rotate && !isBearingTrackingDisabled() && isDismissBearingTrackingOnGesture()) { + setMyBearingTrackingMode(MyBearingTracking.NONE); + } + } + + public void resetTrackingModesIfRequired(CameraPosition cameraPosition) { + resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1); + } } 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 new file mode 100644 index 000000000..1532bb674 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -0,0 +1,143 @@ +package com.mapbox.mapboxsdk.maps; + +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; + +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdate; + +import java.util.concurrent.TimeUnit; + +import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED; + +/** + * Resembles the current Map transformation. + *

+ * Responsible for synchronising {@link CameraPosition} state and notifying {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraChangeListener}. + *

+ */ +class Transform { + + private NativeMapView mapView; + private MapboxMap mapboxMap; + + private CameraPosition cameraPosition; + private MapboxMap.CancelableCallback cameraCancelableCallback; + private MapboxMap.OnCameraChangeListener onCameraChangeListener; + + Transform(NativeMapView mapView, MapboxMap mapboxMap) { + this.mapView = mapView; + this.mapboxMap = mapboxMap; + } + + // + // Camera API + // + + @UiThread + public final CameraPosition getCameraPosition() { + if (cameraPosition == null) { + cameraPosition = invalidateCameraPosition(); + } + return cameraPosition; + } + + @UiThread + final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { + cameraPosition = update.getCameraPosition(mapboxMap); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + cancelTransitions(); + mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); + + // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo` + // invalidate camera position to provide OnCameraChange event. + mapboxMap.invalidateCameraPosition(); + if (callback != null) { + callback.onFinish(); + } + } + + @UiThread + final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator, boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { + cameraPosition = update.getCameraPosition(mapboxMap); + if (resetTrackingMode) { + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + } + + cancelTransitions(); + if (callback != null) { + cameraCancelableCallback = callback; + mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) { + cameraCancelableCallback.onFinish(); + cameraCancelableCallback = null; + mapView.removeOnMapChangedListener(this); + } + } + }); + } + + mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, cameraPosition.zoom, easingInterpolator); + } + + @UiThread + final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { + cameraPosition = update.getCameraPosition(mapboxMap); + mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + + cancelTransitions(); + if (callback != null) { + cameraCancelableCallback = callback; + mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) { + cameraCancelableCallback.onFinish(); + cameraCancelableCallback = null; + mapView.removeOnMapChangedListener(this); + } + } + }); + } + + mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, cameraPosition.zoom); + } + + @UiThread + @Nullable + CameraPosition invalidateCameraPosition() { + CameraPosition cameraPosition = null; + if (mapView != null) { + cameraPosition = new CameraPosition.Builder(mapView.getCameraValues()).build(); + this.cameraPosition = cameraPosition; + if (onCameraChangeListener != null) { + onCameraChangeListener.onCameraChange(this.cameraPosition); + } + } + return cameraPosition; + } + + void cancelTransitions() { + if (cameraCancelableCallback != null) { + cameraCancelableCallback.onCancel(); + cameraCancelableCallback = null; + } + mapView.cancelTransitions(); + } + + @UiThread + void resetNorth() { + cancelTransitions(); + mapView.resetNorth(); + } + + void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) { + this.onCameraChangeListener = listener; + } + + private long getDurationNano(long durationMs) { + return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0; + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java index 776406d55..5a74deef0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java @@ -45,7 +45,7 @@ public class MarkerViewTest { } @Test - public void addMarkerTest() { + public void addMarkerViewTest() { ViewUtils.checkViewIsDisplayed(R.id.mapView); MapboxMap mapboxMap = rule.getActivity().getMapboxMap(); assertEquals("Markers should be empty", 0, mapboxMap.getMarkers().size()); @@ -107,6 +107,8 @@ public class MarkerViewTest { public void perform(UiController uiController, View view) { mapboxMap.getMarkerViewManager().addMarkerViewAdapter(new MarkerViewActivity.TextAdapter(view.getContext(), mapboxMap)); marker = mapboxMap.addMarker(options); + mapboxMap.invalidate(); + uiController.loopMainThreadForAtLeast(250); } } @@ -131,11 +133,11 @@ public class MarkerViewTest { @Override public void perform(UiController uiController, View view) { mapboxMap.selectMarker(marker); - + mapboxMap.invalidate(); + uiController.loopMainThreadForAtLeast(250); } } - @After public void unregisterIdlingResource() { Espresso.unregisterIdlingResources(idlingResource); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java index 053a7fb6b..80f5dda77 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java @@ -231,6 +231,7 @@ public class CameraMoveTest { @Override public void perform(UiController uiController, View view) { mapboxMap.moveCamera(cameraUpdate); + uiController.loopMainThreadForAtLeast(100); } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java index 244759713..50c61b1ce 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java @@ -61,6 +61,13 @@ public class CameraAnimationTypeActivity extends AppCompatActivity implements On } }); + mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() { + @Override + public void onCameraChange(CameraPosition position) { + Log.e(MapboxConstants.TAG, "OnCameraChange: " + position); + } + }); + // handle move button clicks View moveButton = findViewById(R.id.cameraMoveButton); if (moveButton != null) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java index 1f2f7346c..617288635 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java @@ -54,6 +54,14 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe @Override public void onMapReady(@NonNull final MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; + + mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() { + @Override + public void onCameraChange(CameraPosition position) { + Log.e(MapboxConstants.TAG, "OnCameraChange: " + position); + } + }); + // add a listener to FAB FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary)); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 848a1e2ab..6371ddc2b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -1,8 +1,6 @@ package com.mapbox.mapboxsdk.maps; import android.graphics.Color; -import android.graphics.Point; -import android.graphics.PointF; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.Marker; @@ -11,11 +9,8 @@ import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.PolygonOptions; import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.annotations.PolylineOptions; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.geometry.LatLngBounds; import org.junit.Before; import org.junit.Test; @@ -30,7 +25,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -195,19 +189,6 @@ public class MapboxMapTest { assertFalse("MyLocationEnabled should be false", mMapboxMap.isMyLocationEnabled()); } - // - // padding - // - - @Test - public void testPadding() { - mMapboxMap.setOnCameraChangeListener(mOnCameraChangeListener); - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position)); - mMapboxMap.setPadding(0, 0, 0, 0); - verify(mOnCameraChangeListener, times(1)).onCameraChange(position); - } - // // setters/getters interfaces // @@ -260,316 +241,6 @@ public class MapboxMapTest { assertEquals("MyLocationTrackigChangeListener should match", mMyLocationTrackingModeChangeListener, mMapboxMap.getOnMyLocationTrackingModeChangeListener()); } - // - // CameraPosition - // - - @Test - public void testCameraPosition() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - // - // Camera - moveCamera - // - - @Test - public void testNewCameraPositionMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position)); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - // - // Camera - animateCamera - // - - @Test - public void testNewCameraPositionAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position)); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - @Test - public void testNewCameraPositionAnimateCameraWithCallbackParameter() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), null); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - @Test - public void testNewCameraPositionAnimateCameraWithDurationParameter() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 0); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - @Test - public void testNewCameraPositionAnimateCameraWithDurationAndCallbackParameter() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 0, null); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - // - // Camera - easeCamera - // - - @Test - public void testNewCameraPositionEaseCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(position)); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - @Test - public void testNewCameraPositionEaseCameraWithCallbackParameter() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(position), 1000, null); - assertEquals("CameraPosition should be same", position, mMapboxMap.getCameraPosition()); - } - - // - // Camera - LatLng - // - - @Test - public void testLatLngMoveCamera() { - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(4, 5))); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - } - - @Test - public void testLatLngAnimateCamera() { - mMapboxMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(4, 5))); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - } - - @Test - public void testLatLngEaseCamera() { - mMapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(4, 5)), 1000); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - } - - // - // Camera - LatLngZoom - // - - @Test - public void testLatLngZoomMoveCamera() { - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(4, 5), 10)); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - assertTrue("Zoomlevel should be same", 10 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testLatLngZoomAnimateCamera() { - mMapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(4, 5), 10)); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - assertTrue("Zoomlevel should be same", 10 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testLatLngZoomEaseCamera() { - mMapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(4, 5), 10), 1000); - assertEquals("LatLng should be same", new LatLng(4, 5), mMapboxMap.getCameraPosition().target); - assertTrue("Zoomlevel should be same", 10 == mMapboxMap.getCameraPosition().zoom); - } - - // - // Camera - LatLngBounds - // - @Test - public void testLatLngBounds() { - LatLng la = new LatLng(34.053940, -118.242622); - LatLng ny = new LatLng(40.712730, -74.005953); - LatLng centroid = new LatLng( - (la.getLatitude() + ny.getLatitude()) / 2, - (la.getLongitude() + ny.getLongitude()) / 2); - - Projection projection = mock(Projection.class); - when(projection.toScreenLocation(la)).thenReturn(new PointF(20, 20)); - when(projection.toScreenLocation(ny)).thenReturn(new PointF(100, 100)); - when(projection.fromScreenLocation(any(PointF.class))).thenReturn(centroid); - - UiSettings uiSettings = mock(UiSettings.class); - when(uiSettings.getHeight()).thenReturn(1000f); - - mMapboxMap.setProjection(projection); - mMapboxMap.setUiSettings(uiSettings); - - LatLngBounds bounds = new LatLngBounds.Builder().include(la).include(ny).build(); - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 1)); - - assertEquals("LatLng should be same", centroid, mMapboxMap.getCameraPosition().target); - } - - - // - // CameraPositionUpdate - NPX target - // - @Test - public void testCamerePositionUpdateNullTarget() { - LatLng latLng = new LatLng(1, 1); - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(null)); - assertEquals("LatLng should be same", latLng, mMapboxMap.getCameraPosition().target); - } - - // - // Camera - ScrollBy - // - @Test - public void testScrollBy() { - LatLng latLng = new LatLng(1, 1); - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); - mMapboxMap.moveCamera(CameraUpdateFactory.scrollBy(0, 0)); - assertEquals("LatLng should be same", latLng, mMapboxMap.getCameraPosition().target); - mMapboxMap.moveCamera(CameraUpdateFactory.scrollBy(12, 12)); - } - - // - // Camera - Zoom - // - - @Test - public void testZoomInMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.moveCamera(CameraUpdateFactory.zoomIn()); - assertTrue("Zoomlevel should be same", 4 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomOutMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.moveCamera(CameraUpdateFactory.zoomOut()); - assertTrue("Zoomlevel should be same", 2 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.moveCamera(CameraUpdateFactory.zoomBy(3)); - assertTrue("Zoomlevel should be same", 6 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByPointMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.moveCamera(CameraUpdateFactory.zoomBy(3, new Point(0, 0))); - assertTrue("Zoomlevel should be same", 6 == mMapboxMap.getCameraPosition().zoom); - // todo calculate and check LatLng - } - - @Test - public void testZoomToMoveCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.moveCamera(CameraUpdateFactory.zoomTo(12)); - assertTrue("Zoomlevel should be same", 12 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomInAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.animateCamera(CameraUpdateFactory.zoomIn()); - assertTrue("Zoomlevel should be same", 4 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomOutAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.animateCamera(CameraUpdateFactory.zoomOut()); - assertTrue("Zoomlevel should be same", 2 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.animateCamera(CameraUpdateFactory.zoomBy(3)); - assertTrue("Zoomlevel should be same", 6 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomToAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12)); - assertTrue("Zoomlevel should be same", 12 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByPointAnimateCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.animateCamera(CameraUpdateFactory.zoomBy(1, new Point(0, 0))); - assertTrue("Zoomlevel should be same", 4 == mMapboxMap.getCameraPosition().zoom); - // todo calculate and check LatLng - } - - @Test - public void testZoomInEaseCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.easeCamera(CameraUpdateFactory.zoomIn(), 1000); - assertTrue("Zoomlevel should be same", 4 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomOutEaseCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.easeCamera(CameraUpdateFactory.zoomOut(), 1000); - assertTrue("Zoomlevel should be same", 2 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByEaseCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.easeCamera(CameraUpdateFactory.zoomBy(3), 1000); - assertTrue("Zoomlevel should be same", 6 == mMapboxMap.getCameraPosition().zoom); - } - - @Test - public void testZoomByPointCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.easeCamera(CameraUpdateFactory.zoomBy(3, new Point(0, 0)), 1000); - assertTrue("Zoomlevel should be same", 6 == mMapboxMap.getCameraPosition().zoom); - // todo calculate and check LatLng - } - - @Test - public void testZoomToEaseCamera() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setCameraPosition(position); - mMapboxMap.easeCamera(CameraUpdateFactory.zoomTo(12), 1000); - assertTrue("Zoomlevel should be same", 12 == mMapboxMap.getCameraPosition().zoom); - } - - // - // OnCameraChangeListener - // - - @Test - public void testOnCameraChangeListener() { - CameraPosition position = new CameraPosition.Builder().bearing(1).tilt(2).zoom(3).target(new LatLng(4, 5)).build(); - mMapboxMap.setOnCameraChangeListener(mOnCameraChangeListener); - mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position)); - verify(mOnCameraChangeListener, times(1)).onCameraChange(position); - } - // // Annotations // @@ -582,7 +253,7 @@ public class MapboxMapTest { } @Test(expected = InvalidMarkerPositionException.class) - public void testAddMarkerInvalidPosition(){ + public void testAddMarkerInvalidPosition() { new MarkerOptions().getMarker(); } diff --git a/platform/android/bitrise.yml b/platform/android/bitrise.yml index ab1cb8423..e0bf174b0 100644 --- a/platform/android/bitrise.yml +++ b/platform/android/bitrise.yml @@ -55,7 +55,7 @@ workflows: sudo apt-get update && sudo apt-get install -y google-cloud-sdk # Get authentication secret - echo "Downloading Google Cloud authnetication:" + echo "Downloading Google Cloud authentication:" wget -O secret.json "$BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL" - script: title: Build libmapbox-gl.so for armeabi-v7a @@ -98,7 +98,6 @@ workflows: gcloud auth activate-service-account --key-file secret.json --project android-gl-native gcloud beta test android devices list gcloud beta test android run --type instrumentation --app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest.apk --device-ids shamu --os-version-ids 22 --locales en --orientations portrait --timeout 15m - echo "The details are made available as a zipped build artefact on top of this page." - script: title: Download Firebase results run_if: '{{enveq "SKIPCI" "false"}}'