diff options
author | Tobrun <tobrun.van.nuland@gmail.com> | 2016-12-06 13:46:49 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-06 13:46:49 +0100 |
commit | 9a9e7978db67276cfaab97e00f2b56eeb0222b12 (patch) | |
tree | 0da54e64117a64195ee46060e01d270a86c1e45d /platform | |
parent | 890b681b182f7d538237604307da487f3619d1b1 (diff) | |
download | qtlocation-mapboxgl-9a9e7978db67276cfaab97e00f2b56eeb0222b12.tar.gz |
[android] - Refactor dependencies, introduce focused components (#7189)
* [android] - refactor dependencies
* ignore tests
Diffstat (limited to 'platform')
38 files changed, 2668 insertions, 2700 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index 1073818ca4..ce2d3d1577 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -9,6 +9,7 @@ import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.ImageView; import com.mapbox.mapboxsdk.R; @@ -31,27 +32,31 @@ import java.util.Map; */ public class MarkerViewManager { - private Map<MarkerView, View> markerViewMap; + private final ViewGroup markerViewContainer; + private final Map<MarkerView, View> markerViewMap = new HashMap<>(); + private final List<MapboxMap.MarkerViewAdapter> markerViewAdapters = new ArrayList<>(); + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 private MapboxMap mapboxMap; - private MapView mapView; - private List<MapboxMap.MarkerViewAdapter> markerViewAdapters; + private long viewMarkerBoundsUpdateTime; private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; - private ImageMarkerViewAdapter defaultMarkerViewAdapter; /** * Creates an instance of MarkerViewManager. * - * @param mapboxMap the MapboxMap associated with the MarkerViewManager - * @param mapView the MapView associated with the MarkerViewManager + * @param container the ViewGroup associated with the MarkerViewManager */ - public MarkerViewManager(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) { + public MarkerViewManager(@NonNull ViewGroup container) { + this.markerViewContainer = container; + this.markerViewAdapters.add(new ImageMarkerViewAdapter(container.getContext())); + } + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + public void bind(MapboxMap mapboxMap){ this.mapboxMap = mapboxMap; - this.markerViewAdapters = new ArrayList<>(); - this.mapView = mapView; - this.markerViewMap = new HashMap<>(); - this.defaultMarkerViewAdapter = new ImageMarkerViewAdapter(mapView.getContext()); - this.markerViewAdapters.add(defaultMarkerViewAdapter); } /** @@ -415,7 +420,7 @@ public class MarkerViewManager { * </p> */ public void invalidateViewMarkersInVisibleRegion() { - RectF mapViewRect = new RectF(0, 0, mapView.getWidth(), mapView.getHeight()); + RectF mapViewRect = new RectF(0, 0, markerViewContainer.getWidth(), markerViewContainer.getHeight()); List<MarkerView> markers = mapboxMap.getMarkerViewsInRect(mapViewRect); View convertView; @@ -445,7 +450,7 @@ public class MarkerViewManager { // Inflate View convertView = (View) adapter.getViewReusePool().acquire(); - final View adaptedView = adapter.getView(marker, convertView, mapView); + final View adaptedView = adapter.getView(marker, convertView, markerViewContainer); if (adaptedView != null) { adaptedView.setRotationX(marker.getTilt()); adaptedView.setRotation(marker.getRotation()); @@ -464,7 +469,7 @@ public class MarkerViewManager { markerViewMap.put(marker, adaptedView); if (convertView == null) { adaptedView.setVisibility(View.GONE); - mapView.getMarkerViewContainer().addView(adaptedView); + markerViewContainer.addView(adaptedView); } } } @@ -515,7 +520,7 @@ public class MarkerViewManager { for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { if (adapter.getMarkerClass().equals(marker.getClass())) { View convertView = (View) adapter.getViewReusePool().acquire(); - view = adapter.getView(marker, convertView, mapView); + view = adapter.getView(marker, convertView, markerViewContainer); break; } } @@ -523,7 +528,7 @@ public class MarkerViewManager { if (view != null) { if (marker.getWidth() == 0) { - if(view.getMeasuredWidth()==0) { + if (view.getMeasuredWidth() == 0) { //Ensure the marker's view is measured first view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); } @@ -546,6 +551,10 @@ public class MarkerViewManager { } } + public ViewGroup getMarkerViewContainer() { + return markerViewContainer; + } + /** * Default MarkerViewAdapter used for base class of {@link MarkerView} to adapt a MarkerView to * an ImageView. diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java index 9c96450a4c..04105ebc59 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -257,7 +257,7 @@ public final class CameraUpdateFactory { float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width; float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height; minScale = scaleX < scaleY ? scaleX : scaleY; - zoom = projection.calculateZoom(minScale); + zoom = calculateZoom(mapboxMap, minScale); zoom = MathUtils.clamp(zoom, mapboxMap.getMinZoom(), mapboxMap.getMaxZoom()); } @@ -275,6 +275,16 @@ public final class CameraUpdateFactory { .bearing(0) .build(); } + + /** + * Calculates a zoom level based on minimum scale and current scale from MapView + * + * @param minScale The minimum scale to calculate the zoom level. + * @return zoom level that fits the MapView. + */ + public double calculateZoom(MapboxMap mapboxMap, float minScale) { + return Math.log(mapboxMap.getCameraPosition().zoom * minScale) / Math.log(2); + } } static final class CameraMoveUpdate implements CameraUpdate { 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 9e08d93bfc..c1cf966eed 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 @@ -1,9 +1,11 @@ package com.mapbox.mapboxsdk.maps; +import android.graphics.PointF; import android.graphics.RectF; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.LongSparseArray; +import android.view.ViewGroup; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; @@ -18,6 +20,7 @@ import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.annotations.PolylineOptions; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -32,30 +35,38 @@ import java.util.List; */ class AnnotationManager implements MapView.OnMapChangedListener { - private NativeMapView nativeMapView; - private IconManager iconManager; - private InfoWindowManager infoWindowManager; - private MarkerViewManager markerViewManager; + private final NativeMapView nativeMapView; + private final MapView mapView; + private final IconManager iconManager; + private final InfoWindowManager infoWindowManager = new InfoWindowManager(); + private final MarkerViewManager markerViewManager; + private final LongSparseArray<Annotation> annotations = new LongSparseArray<>(); + private final List<Marker> selectedMarkers = new ArrayList<>(); - private LongSparseArray<Annotation> annotations; - private List<Marker> selectedMarkers; + private MapboxMap mapboxMap; private MapboxMap.OnMarkerClickListener onMarkerClickListener; private boolean isWaitingForRenderInvoke; - AnnotationManager(NativeMapView view, IconManager iconManager, InfoWindowManager manager) { + AnnotationManager(NativeMapView view, MapView mapView, MarkerViewManager markerViewManager) { this.nativeMapView = view; - this.iconManager = iconManager; - this.infoWindowManager = manager; - this.selectedMarkers = new ArrayList<>(); - this.annotations = new LongSparseArray<>(); - + this.mapView = mapView; + this.iconManager = new IconManager(nativeMapView); + this.markerViewManager = markerViewManager; if (view != null) { // null checking needed for unit tests view.addOnMapChangedListener(this); } } + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + AnnotationManager bind(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + this.markerViewManager.bind(mapboxMap); + return this; + } + @Override public void onMapChanged(@MapView.MapChange int change) { if (isWaitingForRenderInvoke && change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) { @@ -280,7 +291,7 @@ class AnnotationManager implements MapView.OnMapChangedListener { onMarkerClickListener = listener; } - void selectMarker(@NonNull Marker marker, @NonNull MapboxMap mapboxMap) { + void selectMarker(@NonNull Marker marker) { if (selectedMarkers.contains(marker)) { return; } @@ -303,7 +314,7 @@ class AnnotationManager implements MapView.OnMapChangedListener { } if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) { - infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView())); + infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapView)); } } @@ -564,14 +575,11 @@ class AnnotationManager implements MapView.OnMapChangedListener { return polylines; } - // - // MarkerViewManager - // + InfoWindowManager getInfoWindowManager() { + return infoWindowManager; + } - MarkerViewManager getMarkerViewManager(MapboxMap mapboxMap) { - if (markerViewManager == null) { - this.markerViewManager = new MarkerViewManager(mapboxMap, mapboxMap.getMapView()); - } + MarkerViewManager getMarkerViewManager() { return markerViewManager; } @@ -589,12 +597,13 @@ class AnnotationManager implements MapView.OnMapChangedListener { for (Marker marker : selectedMarkers) { if (marker.isInfoWindowShown()) { marker.hideInfoWindow(); - marker.showInfoWindow(mapboxMap, mapboxMap.getMapView()); + marker.showInfoWindow(mapboxMap, mapView); } } } void reloadMarkers() { + iconManager.reloadIcons(); int count = annotations.size(); for (int i = 0; i < count; i++) { Annotation annotation = annotations.get(i); @@ -606,4 +615,58 @@ class AnnotationManager implements MapView.OnMapChangedListener { } } } + + // + // Click event + // + + boolean onTap(PointF tapPoint, float screenDensity) { + float toleranceSides = 4 * screenDensity; + float toleranceTopBottom = 10 * screenDensity; + + RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides, + tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom, + tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides, + tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom); + + List<Marker> nearbyMarkers = getMarkersInRect(tapRect); + long newSelectedMarkerId = -1; + + if (nearbyMarkers != null && nearbyMarkers.size() > 0) { + Collections.sort(nearbyMarkers); + for (Marker nearbyMarker : nearbyMarkers) { + boolean found = false; + for (Marker selectedMarker : selectedMarkers) { + if (selectedMarker.equals(nearbyMarker)) { + found = true; + } + } + if (!found) { + newSelectedMarkerId = nearbyMarker.getId(); + break; + } + } + } + + if (newSelectedMarkerId >= 0) { + List<Annotation> annotations = getAnnotations(); + int count = annotations.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotations.get(i); + if (annotation instanceof Marker) { + if (annotation.getId() == newSelectedMarkerId) { + if (selectedMarkers.isEmpty() || !selectedMarkers.contains(annotation)) { + if (!(annotation instanceof MarkerView)) { + selectMarker((Marker) annotation); + } else { + markerViewManager.onClickMarkerView((MarkerView) annotation); + } + } + return true; + } + } + } + } + return false; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassViewSettings.java deleted file mode 100644 index 3e1b14d641..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CompassViewSettings.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -/** - * Settings for the overlain views of a MapboxMap. Used by UiSettings. - */ -class CompassViewSettings extends ViewSettings{ - - private boolean fadeFacingNorth = true; - - public CompassViewSettings() { - super(); - } - - public boolean isFadeFacingNorth() { - return fadeFacingNorth; - } - - public void setFadeFacingNorth(boolean fadeFacingNorth) { - this.fadeFacingNorth = fadeFacingNorth; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java new file mode 100644 index 0000000000..5f20155119 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java @@ -0,0 +1,8 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.PointF; + +public interface FocalPointChangeListener { + + void onFocalPointChanged(PointF pointF); +} 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 new file mode 100644 index 0000000000..0df5491535 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -0,0 +1,601 @@ +package com.mapbox.mapboxsdk.maps; + +import android.content.Context; +import android.graphics.PointF; +import android.support.annotation.NonNull; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.view.ScaleGestureDetectorCompat; +import android.util.Log; +import android.view.InputDevice; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.ViewConfiguration; + +import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; +import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector; +import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.telemetry.MapboxEvent; + +import timber.log.Timber; + +/** + * Manages gestures events on a MapView. + * <p> + * Relies on gesture detection code in almeros.android.multitouch.gesturedetectors. + * </p> + */ +final class MapGestureDetector { + + private final Transform transform; + private final Projection projection; + private final UiSettings uiSettings; + private final TrackingSettings trackingSettings; + private final AnnotationManager annotationManager; + + private final GestureDetectorCompat gestureDetector; + private final ScaleGestureDetector scaleGestureDetector; + private final RotateGestureDetector rotateGestureDetector; + private final ShoveGestureDetector shoveGestureDetector; + + private MapboxMap.OnMapClickListener onMapClickListener; + private MapboxMap.OnMapLongClickListener onMapLongClickListener; + private MapboxMap.OnFlingListener onFlingListener; + private MapboxMap.OnScrollListener onScrollListener; + + private PointF focalPoint; + + private boolean twoTap = false; + private boolean zoomStarted = false; + private boolean dragStarted = false; + private boolean quickZoom = false; + private boolean scrollInProgress = false; + + MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, + TrackingSettings trackingSettings, AnnotationManager annotationManager) { + this.annotationManager = annotationManager; + this.transform = transform; + this.projection = projection; + this.uiSettings = uiSettings; + this.trackingSettings = trackingSettings; + + // Touch gesture detectors + gestureDetector = new GestureDetectorCompat(context, new GestureListener()); + gestureDetector.setIsLongpressEnabled(true); + scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener()); + ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true); + rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener()); + shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener()); + } + + /** + * Set the gesture focal point. + * <p> + * this is the center point used for calculate transformations from gestures, value is + * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. + * </p> + * + * @param focalPoint the center point for gestures + */ + void setFocalPoint(PointF focalPoint) { + if (focalPoint == null) { + // resetting focal point, + if (uiSettings.getFocalPoint() != null) { + // using user provided one to reset + focalPoint = uiSettings.getFocalPoint(); + } + } + this.focalPoint = focalPoint; + } + + + /** + * Called when user touches the screen, all positions are absolute. + * <p> + * Forwards event to the related gesture detectors. + * </p> + * + * @param event the MotionEvent + * @return True if touch event is handled + */ + boolean onTouchEvent(@NonNull MotionEvent event) { + // Check and ignore non touch or left clicks + if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + return false; + } + + // Check two finger gestures first + rotateGestureDetector.onTouchEvent(event); + scaleGestureDetector.onTouchEvent(event); + shoveGestureDetector.onTouchEvent(event); + + // Handle two finger tap + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + // First pointer down + transform.setGestureInProgress(true); + break; + + case MotionEvent.ACTION_POINTER_DOWN: + // Second pointer down + twoTap = event.getPointerCount() == 2 + && uiSettings.isZoomGesturesEnabled(); + if (twoTap) { + // Confirmed 2nd Finger Down + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY(), transform.getZoom()); + } + break; + + case MotionEvent.ACTION_POINTER_UP: + // Second pointer up + break; + + case MotionEvent.ACTION_UP: + // First pointer up + long tapInterval = event.getEventTime() - event.getDownTime(); + boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout(); + boolean inProgress = rotateGestureDetector.isInProgress() + || scaleGestureDetector.isInProgress() + || shoveGestureDetector.isInProgress(); + + if (twoTap && isTap && !inProgress) { + if (focalPoint != null) { + transform.zoom(false, focalPoint.x, focalPoint.y); + } else { + PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); + transform.zoom(false, focalPoint.x, focalPoint.y); + } + twoTap = false; + return true; + } + + // Scroll / Pan Has Stopped + if (scrollInProgress) { + MapboxEvent.trackGestureDragEndEvent(projection, event.getX(), event.getY(), transform.getZoom()); + scrollInProgress = false; + } + + twoTap = false; + transform.setGestureInProgress(false); + break; + + case MotionEvent.ACTION_CANCEL: + twoTap = false; + transform.setGestureInProgress(false); + break; + } + + return gestureDetector.onTouchEvent(event); + } + + /** + * Called for events that don't fit the other handlers. + * <p> + * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. + * </p> + * + * @param event The MotionEvent occured + * @return True is the event is handled + */ + boolean onGenericMotionEvent(MotionEvent event) { + // Mouse events + //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { + // Choose the action + switch (event.getActionMasked()) { + // Mouse scrolls + case MotionEvent.ACTION_SCROLL: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Get the vertical scroll amount, one click = 1 + float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + + // Scale the map by the appropriate power of two factor + transform.zoomBy(Math.pow(2.0, scrollDist), event.getX(), event.getY()); + + return true; + + default: + // We are not interested in this event + return false; + } + } + + // We are not interested in this event + return false; + } + + + /** + * Responsible for handling one finger gestures. + */ + private class GestureListener extends android.view.GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDown(MotionEvent event) { + return true; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent e) { + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + switch (e.getAction()) { + case MotionEvent.ACTION_DOWN: + break; + case MotionEvent.ACTION_MOVE: + break; + case MotionEvent.ACTION_UP: + if (quickZoom) { + // insert here? + quickZoom = false; + break; + } + + // Single finger double tap + if (focalPoint != null) { + // User provided focal point + transform.zoom(true, focalPoint.x, focalPoint.y); + } else { + // Zoom in on gesture + transform.zoom(true, e.getX(), e.getY()); + } + break; + } + + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY(), transform.getZoom()); + + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent motionEvent) { + // Cancel any animation + transform.cancelTransitions(); + return true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent motionEvent) { + PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + boolean tapHandled = annotationManager.onTap(tapPoint, uiSettings.getPixelRatio()); + + if (!tapHandled) { + if (uiSettings.isDeselectMarkersOnTap()) { + // deselect any selected marker + annotationManager.deselectMarkers(); + } + + // notify app of map click + if (onMapClickListener != null) { + onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); + } + } + + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY(), transform.getZoom()); + return true; + } + + @Override + public void onLongPress(MotionEvent motionEvent) { + if (onMapLongClickListener != null && !quickZoom) { + onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY()))); + } + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + trackingSettings.resetTrackingModesIfRequired(true, false); + + double decelerationRate = 1; + + // Cancel any animation + transform.cancelTransitions(); + + float screenDensity = uiSettings.getPixelRatio(); + double offsetX = velocityX * decelerationRate / 4 / screenDensity; + double offsetY = velocityY * decelerationRate / 4 / screenDensity; + + transform.setGestureInProgress(true); + transform.moveBy(offsetX, offsetY, (long) (decelerationRate * 1000.0f)); + transform.setGestureInProgress(false); + + if (onFlingListener != null) { + onFlingListener.onFling(); + } + + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY(), transform.getZoom()); + return true; + } + + // Called for drags + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!scrollInProgress) { + scrollInProgress = true; + } + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + if (dragStarted) { + return false; + } + + // reset tracking if needed + trackingSettings.resetTrackingModesIfRequired(true, false); + // Cancel any animation + transform.cancelTransitions(); + + // Scroll the map + transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); + + if (onScrollListener != null) { + onScrollListener.onScroll(); + } + return true; + } + } + + /** + * Responsible for handling two finger gestures and double-tap drag gestures. + */ + private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + + long beginTime = 0; + float scaleFactor = 1.0f; + + // Called when two fingers first touch the screen + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + return true; + } + + // Called when fingers leave screen + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + beginTime = 0; + scaleFactor = 1.0f; + zoomStarted = false; + } + + // Called each time a finger moves + // Called for pinch zooms and quickzooms/quickscales + @Override + public boolean onScale(ScaleGestureDetector detector) { + if (!uiSettings.isZoomGesturesEnabled()) { + return super.onScale(detector); + } + + // If scale is large enough ignore a tap + scaleFactor *= detector.getScaleFactor(); + if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) { + zoomStarted = true; + } + + // Ignore short touches in case it is a tap + // Also ignore small scales + long time = detector.getEventTime(); + long interval = time - beginTime; + if (!zoomStarted && (interval <= ViewConfiguration.getTapTimeout())) { + return false; + } + + if (!zoomStarted) { + return false; + } + + if (dragStarted) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Gesture is a quickzoom if there aren't two fingers + quickZoom = !twoTap; + + // make an assumption here; if the zoom center is specified by the gesture, it's NOT going + // to be in the center of the map. Therefore the zoom will translate the map center, so tracking + // should be disabled. + + trackingSettings.resetTrackingModesIfRequired(!quickZoom, false); + // Scale the map + if (focalPoint != null) { + // arround user provided focal point + transform.zoomBy(detector.getScaleFactor(), focalPoint.x, focalPoint.y); + } else if (quickZoom) { + // around center map + transform.zoomBy(detector.getScaleFactor(), uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } else { + // around gesture + transform.zoomBy(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); + } + + return true; + } + } + + /** + * Responsible for handling rotation gestures. + */ + private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { + + long beginTime = 0; + float totalAngle = 0.0f; + boolean started = false; + + // Called when two fingers first touch the screen + @Override + public boolean onRotateBegin(RotateGestureDetector detector) { + if (!trackingSettings.isRotateGestureCurrentlyEnabled()) { + return false; + } + + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + return true; + } + + // Called when the fingers leave the screen + @Override + public void onRotateEnd(RotateGestureDetector detector) { + beginTime = 0; + totalAngle = 0.0f; + started = false; + } + + // Called each time one of the two fingers moves + // Called for rotation + @Override + public boolean onRotate(RotateGestureDetector detector) { + if (!trackingSettings.isRotateGestureCurrentlyEnabled() || dragStarted) { + return false; + } + + // If rotate is large enough ignore a tap + // Also is zoom already started, don't rotate + totalAngle += detector.getRotationDegreesDelta(); + if (!zoomStarted && ((totalAngle > 20.0f) || (totalAngle < -20.0f))) { + started = true; + } + + // Ignore short touches in case it is a tap + // Also ignore small rotate + long time = detector.getEventTime(); + long interval = time - beginTime; + if (!started && (interval <= ViewConfiguration.getTapTimeout())) { + return false; + } + + if (!started) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // rotation constitutes translation of anything except the center of + // rotation, so cancel both location and bearing tracking if required + + trackingSettings.resetTrackingModesIfRequired(true, true); + + // Get rotate value + double bearing = transform.getRawBearing(); + bearing += detector.getRotationDegreesDelta(); + + // Rotate the map + if (focalPoint != null) { + // User provided focal point + transform.setBearing(bearing, focalPoint.x, focalPoint.y); + } else { + // around gesture + transform.setBearing(bearing, detector.getFocusX(), detector.getFocusY()); + } + return true; + } + } + + /** + * Responsible for handling 2 finger shove gestures. + */ + private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { + + long beginTime = 0; + float totalDelta = 0.0f; + boolean started = false; + + @Override + public boolean onShoveBegin(ShoveGestureDetector detector) { + if (!uiSettings.isTiltGesturesEnabled()) { + return false; + } + + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); + return true; + } + + @Override + public void onShoveEnd(ShoveGestureDetector detector) { + beginTime = 0; + totalDelta = 0.0f; + started = false; + dragStarted = false; + } + + @Override + public boolean onShove(ShoveGestureDetector detector) { + if (!uiSettings.isTiltGesturesEnabled()) { + return false; + } + + // If tilt is large enough ignore a tap + // Also if zoom already started, don't tilt + totalDelta += detector.getShovePixelsDelta(); + if (!zoomStarted && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) { + started = true; + } + + // Ignore short touches in case it is a tap + // Also ignore small tilt + long time = detector.getEventTime(); + long interval = time - beginTime; + if (!started && (interval <= ViewConfiguration.getTapTimeout())) { + return false; + } + + if (!started) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Get tilt value (scale and clamp) + double pitch = transform.getTilt(); + pitch -= 0.1 * detector.getShovePixelsDelta(); + pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); + + // Tilt the map + transform.setTilt(pitch); + + dragStarted = true; + + return true; + } + } + + void setOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) { + this.onMapClickListener = onMapClickListener; + } + + void setOnMapLongClickListener(MapboxMap.OnMapLongClickListener onMapLongClickListener) { + this.onMapLongClickListener = onMapLongClickListener; + } + + void setOnFlingListener(MapboxMap.OnFlingListener onFlingListener) { + this.onFlingListener = onFlingListener; + } + + void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) { + this.onScrollListener = onScrollListener; + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java new file mode 100644 index 0000000000..09b4a2c9ca --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -0,0 +1,264 @@ +package com.mapbox.mapboxsdk.maps; + +import android.os.Handler; +import android.support.annotation.NonNull; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +/** + * Manages key events on a MapView. + * <p> + * <ul> + * <li> Uses {@link Transform} to change the map state</li> + * <li> Uses {@link TrackingSettings} to verify validity of the current tracking mode.</li> + * <li> Uses {@link UiSettings} to verify validity of user restricted movement.</li> + * </ul> + * <p> + */ +final class MapKeyListener { + + private final TrackingSettings trackingSettings; + private final Transform transform; + private final UiSettings uiSettings; + + private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; + + MapKeyListener(@NonNull Transform transform, @NonNull TrackingSettings trackingSettings, @NonNull UiSettings uiSettings) { + this.transform = transform; + this.trackingSettings = trackingSettings; + this.uiSettings = uiSettings; + } + + /** + * Called when the user presses a key, alse called for repeated keys held down. + * + * @param keyCode the id of the pressed key + * @param event the related key event + * @return true if the wevent is handled + */ + boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { + // If the user has held the scroll key down for a while then accelerate + // the scroll speed + double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; + + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + event.startTracking(); + return true; + + case KeyEvent.KEYCODE_DPAD_LEFT: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move left + transform.moveBy(scrollDist, 0.0, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move right + transform.moveBy(-scrollDist, 0.0, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_UP: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move up + transform.moveBy(0.0, scrollDist, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_DOWN: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Move down + transform.moveBy(0.0, -scrollDist, 0 /*no animation*/); + return true; + + default: + // We are not interested in this key + return false; + } + } + + /** + * Called when the user long presses a key that is being tracked. + * + * @param keyCode the id of the long pressed key + * @param event the related key event + * @return true if event is handled + */ + boolean onKeyLongPress(int keyCode, KeyEvent event) { + // Check which key was pressed via hardware/real key code + switch (keyCode) { + // Tell the system to track these keys for long presses on + // onKeyLongPress is fired + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Zoom out + transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return true; + + default: + // We are not interested in this key + return false; + } + } + + /** + * Called when the user releases a key. + * + * @param keyCode the id of the released key + * @param event the related key event + * @return true if the event is handled + */ + boolean onKeyUp(int keyCode, KeyEvent event) { + // Check if the key action was canceled (used for virtual keyboards) + if (event.isCanceled()) { + return false; + } + + // Check which key was pressed via hardware/real key code + // Note if keyboard does not have physical key (ie primary non-shifted + // key) then it will not appear here + // Must use the key character map as physical to character is not + // fixed/guaranteed + switch (keyCode) { + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Zoom in + transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return true; + } + + // We are not interested in this key + return false; + } + + /** + * Called for trackball events, all motions are relative in device specific units. + * + * @param event the related motion event + * @return true if the event is handled + */ + boolean onTrackballEvent(MotionEvent event) { + // Choose the action + switch (event.getActionMasked()) { + // The trackball was rotated + case MotionEvent.ACTION_MOVE: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } + + // Cancel any animation + transform.cancelTransitions(); + + // Scroll the map + transform.moveBy(-10.0 * event.getX(), -10.0 * event.getY(), 0 /*no animation*/); + return true; + + // Trackball was pushed in so start tracking and tell system we are + // interested + // We will then get the up action + case MotionEvent.ACTION_DOWN: + // Set up a delayed callback to check if trackball is still + // After waiting the system long press time out + if (currentTrackballLongPressTimeOut != null) { + currentTrackballLongPressTimeOut.cancel(); + currentTrackballLongPressTimeOut = null; + } + currentTrackballLongPressTimeOut = new TrackballLongPressTimeOut(); + new Handler().postDelayed(currentTrackballLongPressTimeOut, + ViewConfiguration.getLongPressTimeout()); + return true; + + // Trackball was released + case MotionEvent.ACTION_UP: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } + + // Only handle if we have not already long pressed + if (currentTrackballLongPressTimeOut != null) { + // Zoom in + transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } + return true; + + // Trackball was cancelled + case MotionEvent.ACTION_CANCEL: + if (currentTrackballLongPressTimeOut != null) { + currentTrackballLongPressTimeOut.cancel(); + currentTrackballLongPressTimeOut = null; + } + return true; + + default: + // We are not interested in this event + return false; + } + } + + /** + * This class implements the trackball long press time out callback + */ + private class TrackballLongPressTimeOut implements Runnable { + + // Track if we have been cancelled + private boolean cancelled; + + TrackballLongPressTimeOut() { + cancelled = false; + } + + // Cancel the timeout + public void cancel() { + cancelled = true; + } + + // Called when long press time out expires + @Override + public void run() { + // Check if the trackball is still pressed + if (!cancelled) { + // Zoom out + transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + + // Ensure the up action is not run + currentTrackballLongPressTimeOut = null; + } + } + } +} 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 3fe9a67f3c..cd7caf395d 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,7 +1,5 @@ package com.mapbox.mapboxsdk.maps; -import android.Manifest; -import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.app.Fragment; @@ -11,66 +9,47 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.PointF; -import android.graphics.RectF; import android.graphics.SurfaceTexture; -import android.location.Location; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Bundle; import android.support.annotation.CallSuper; -import android.support.annotation.FloatRange; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.GestureDetectorCompat; -import android.support.v4.view.ScaleGestureDetectorCompat; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.util.AttributeSet; -import timber.log.Timber; -import android.view.GestureDetector; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.ScaleGestureDetector; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.TextureView; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ZoomButtonsController; -import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector; -import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector; import com.mapbox.mapboxsdk.MapboxAccountManager; import com.mapbox.mapboxsdk.R; -import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.InfoWindow; -import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerView; +import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.constants.Style; -import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.LocationListener; import com.mapbox.mapboxsdk.location.LocationServices; import com.mapbox.mapboxsdk.maps.widgets.CompassView; @@ -78,17 +57,15 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import com.mapbox.mapboxsdk.telemetry.MapboxEvent; import com.mapbox.mapboxsdk.telemetry.MapboxEventManager; -import com.mapbox.mapboxsdk.utils.ColorUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; -import java.util.Collections; import java.util.Hashtable; import java.util.Iterator; import java.util.List; -import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing; +import timber.log.Timber; /** * <p> @@ -107,8 +84,6 @@ import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing; public class MapView extends FrameLayout { private MapboxMap mapboxMap; - private IconManager iconManager; - private AnnotationManager annotationManager; private boolean initialLoad; private boolean destroyed; @@ -116,42 +91,18 @@ public class MapView extends FrameLayout { private NativeMapView nativeMapView; private boolean hasSurface = false; - private ViewGroup markerViewContainer; private CompassView compassView; - private ImageView logoView; - private ImageView attributionsView; private MyLocationView myLocationView; private LocationListener myLocationListener; - private Projection projection; + private MapGestureDetector mapGestureDetector; + private MapKeyListener mapKeyListener; - private ZoomButtonsController zoomButtonsController; private ConnectivityReceiver connectivityReceiver; - private float screenDensity = 1.0f; - - private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; - private GestureDetectorCompat gestureDetector; - private ScaleGestureDetector scaleGestureDetector; - private RotateGestureDetector rotateGestureDetector; - private ShoveGestureDetector shoveGestureDetector; - private boolean twoTap = false; - private boolean zoomStarted = false; - private boolean dragStarted = false; - private boolean quickZoom = false; - private boolean scrollInProgress = false; - - private int contentPaddingLeft; - private int contentPaddingTop; - private int contentPaddingRight; - private int contentPaddingBottom; - - private PointF focalPoint; - - private String styleUrl = Style.MAPBOX_STREETS; - private boolean styleWasSet = false; - - private List<OnMapReadyCallback> onMapReadyCallbackList; + + private List<OnMapReadyCallback> onMapReadyCallbackList = new ArrayList<>(); private SnapshotRequest snapshotRequest; + private ZoomButtonsController zoomButtonsController; private boolean onStartCalled; private boolean onStopCalled; @@ -175,21 +126,20 @@ public class MapView extends FrameLayout { } @UiThread - public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) { + public MapView(@NonNull Context context, @NonNull MapboxMapOptions options) { super(context); initialize(context, options); } - private void initialize(@NonNull Context context, @NonNull MapboxMapOptions options) { + private void initialize(@NonNull final Context context, @NonNull final MapboxMapOptions options) { if (isInEditMode()) { // if we are in an editor mode we show an image of a map LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this); return; } + // TODO distill into singular purpose methods/classes initialLoad = true; - onMapReadyCallbackList = new ArrayList<>(); - View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this); setWillNotDraw(false); @@ -204,153 +154,61 @@ public class MapView extends FrameLayout { } nativeMapView = new NativeMapView(this); - iconManager = new IconManager(nativeMapView); - mapboxMap = new MapboxMap(this, iconManager); - annotationManager = mapboxMap.getAnnotationManager(); - projection = mapboxMap.getProjection(); + + // inflate overlain Views + compassView = (CompassView) view.findViewById(R.id.compassView); + myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); + ImageView logoView = (ImageView) view.findViewById(R.id.logoView); + ImageView attributionsView = (ImageView) view.findViewById(R.id.attributionView); + attributionsView.setOnClickListener(new AttributionOnClickListener(this)); + ViewGroup markerViewContainer = (ViewGroup) findViewById(R.id.markerViewContainer); + + // interface for focal point invalidation + FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator(); + + // interface for registering touch listeners + RegisterTouchListener registerTouchListener = new RegisterTouchListener(); + + // setup components for MapboxMap creation + Projection projection = new Projection(nativeMapView); + UiSettings uiSettings = new UiSettings(projection, focalPointInvalidator, compassView, attributionsView, logoView); + TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator); + MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(projection, myLocationView, trackingSettings); + MarkerViewManager markerViewManager = new MarkerViewManager(markerViewContainer); + AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, markerViewManager); + Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings); + mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, projection, registerTouchListener, annotationManager); + + // active user input + mapGestureDetector = new MapGestureDetector(context, mapboxMap.getTransform(), projection, uiSettings, trackingSettings, annotationManager); + mapKeyListener = new MapKeyListener(mapboxMap.getTransform(), trackingSettings, uiSettings); + + // attach widgets to MapboxMap + compassView.setMapboxMap(mapboxMap); + myLocationView.setMapboxMap(mapboxMap); // Ensure this view is interactable setClickable(true); setLongClickable(true); setFocusable(true); setFocusableInTouchMode(true); + requestDisallowInterceptTouchEvent(true); requestFocus(); - // Touch gesture detectors - gestureDetector = new GestureDetectorCompat(context, new GestureListener()); - gestureDetector.setIsLongpressEnabled(true); - scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener()); - ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true); - rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener()); - shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener()); - - zoomButtonsController = new ZoomButtonsController(this); - zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION); - zoomButtonsController.setOnZoomListener(new OnZoomListener()); - // Connectivity onConnectivityChanged(isConnected()); - markerViewContainer = (ViewGroup) view.findViewById(R.id.markerViewContainer); - - myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); - myLocationView.setMapboxMap(mapboxMap); - - compassView = (CompassView) view.findViewById(R.id.compassView); - compassView.setMapboxMap(mapboxMap); - - logoView = (ImageView) view.findViewById(R.id.logoView); - - // Setup Attributions control - attributionsView = (ImageView) view.findViewById(R.id.attributionView); - attributionsView.setOnClickListener(new AttributionOnClickListener(this)); - - screenDensity = context.getResources().getDisplayMetrics().density; + // configure the zoom button controller + zoomButtonsController = new ZoomButtonsController(MapView.this); + zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION); + zoomButtonsController.setOnZoomListener(new OnZoomListener(mapboxMap)); - setInitialState(options); + mapboxMap.initialise(context, options); // Shows the zoom controls if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { - mapboxMap.getUiSettings().setZoomControlsEnabled(true); - } - } - - private void setInitialState(MapboxMapOptions options) { - mapboxMap.setDebugActive(options.getDebugActive()); - - CameraPosition position = options.getCamera(); - if (position != null && !position.equals(CameraPosition.DEFAULT)) { - mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position)); - myLocationView.setTilt(position.tilt); - } - - // api base url - String apiBaseUrl = options.getApiBaseUrl(); - if (!TextUtils.isEmpty(apiBaseUrl)) { - setApiBaseUrl(apiBaseUrl); - } - - // access token - String accessToken = options.getAccessToken(); - if (!TextUtils.isEmpty(accessToken)) { - mapboxMap.setAccessToken(accessToken); - } - - // style url - String style = options.getStyle(); - if (!TextUtils.isEmpty(style)) { - styleUrl = style; - } - - // MyLocationView - MyLocationViewSettings myLocationViewSettings = mapboxMap.getMyLocationViewSettings(); - myLocationViewSettings.setForegroundDrawable( - options.getMyLocationForegroundDrawable(), options.getMyLocationForegroundBearingDrawable()); - myLocationViewSettings.setForegroundTintColor(options.getMyLocationForegroundTintColor()); - myLocationViewSettings.setBackgroundDrawable( - options.getMyLocationBackgroundDrawable(), options.getMyLocationBackgroundPadding()); - myLocationViewSettings.setBackgroundTintColor(options.getMyLocationBackgroundTintColor()); - myLocationViewSettings.setAccuracyAlpha(options.getMyLocationAccuracyAlpha()); - myLocationViewSettings.setAccuracyTintColor(options.getMyLocationAccuracyTintColor()); - mapboxMap.setMyLocationEnabled(options.getLocationEnabled()); - - // Enable gestures - UiSettings uiSettings = mapboxMap.getUiSettings(); - uiSettings.setZoomGesturesEnabled(options.getZoomGesturesEnabled()); - uiSettings.setZoomGestureChangeAllowed(options.getZoomGesturesEnabled()); - uiSettings.setScrollGesturesEnabled(options.getScrollGesturesEnabled()); - uiSettings.setScrollGestureChangeAllowed(options.getScrollGesturesEnabled()); - uiSettings.setRotateGesturesEnabled(options.getRotateGesturesEnabled()); - uiSettings.setRotateGestureChangeAllowed(options.getRotateGesturesEnabled()); - uiSettings.setTiltGesturesEnabled(options.getTiltGesturesEnabled()); - uiSettings.setTiltGestureChangeAllowed(options.getTiltGesturesEnabled()); - - // Ui Controls - uiSettings.setZoomControlsEnabled(options.getZoomControlsEnabled()); - - // Zoom - mapboxMap.setMaxZoom(options.getMaxZoom()); - mapboxMap.setMinZoom(options.getMinZoom()); - - // Compass - uiSettings.setCompassEnabled(options.getCompassEnabled()); - uiSettings.setCompassGravity(options.getCompassGravity()); - int[] compassMargins = options.getCompassMargins(); - if (compassMargins != null) { - uiSettings.setCompassMargins(compassMargins[0], compassMargins[1], compassMargins[2], compassMargins[3]); - } else { - int tenDp = (int) getResources().getDimension(R.dimen.mapbox_ten_dp); - uiSettings.setCompassMargins(tenDp, tenDp, tenDp, tenDp); - } - uiSettings.setCompassFadeFacingNorth(options.getCompassFadeFacingNorth()); - - // Logo - uiSettings.setLogoEnabled(options.getLogoEnabled()); - uiSettings.setLogoGravity(options.getLogoGravity()); - int[] logoMargins = options.getLogoMargins(); - if (logoMargins != null) { - uiSettings.setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]); - } else { - int sixteenDp = (int) getResources().getDimension(R.dimen.mapbox_sixteen_dp); - uiSettings.setLogoMargins(sixteenDp, sixteenDp, sixteenDp, sixteenDp); - } - - // Attribution - uiSettings.setAttributionEnabled(options.getAttributionEnabled()); - uiSettings.setAttributionGravity(options.getAttributionGravity()); - int[] attributionMargins = options.getAttributionMargins(); - if (attributionMargins != null) { - uiSettings.setAttributionMargins(attributionMargins[0], attributionMargins[1], attributionMargins[2], attributionMargins[3]); - } else { - Resources resources = getResources(); - int sevenDp = (int) resources.getDimension(R.dimen.mapbox_seven_dp); - int seventySixDp = (int) resources.getDimension(R.dimen.mapbox_seventy_six_dp); - uiSettings.setAttributionMargins(seventySixDp, sevenDp, sevenDp, sevenDp); + uiSettings.setZoomControlsEnabled(true); } - - int attributionTintColor = options.getAttributionTintColor(); - uiSettings.setAttributionTintColor(attributionTintColor != -1 - ? attributionTintColor : ColorUtils.getPrimaryColor(getContext())); } // @@ -370,17 +228,20 @@ public class MapView extends FrameLayout { */ @UiThread public void onCreate(@Nullable Bundle savedInstanceState) { + // TODO distill into singular purpose methods/classes String accessToken = mapboxMap.getAccessToken(); if (TextUtils.isEmpty(accessToken)) { accessToken = MapboxAccountManager.getInstance().getAccessToken(); - mapboxMap.setAccessToken(accessToken); + nativeMapView.setAccessToken(accessToken); } else { // user provided access token through xml attributes, need to start MapboxAccountManager MapboxAccountManager.start(getContext(), accessToken); + nativeMapView.setAccessToken(accessToken); } // Force a check for an access token MapboxAccountManager.validateAccessToken(accessToken); + nativeMapView.setAccessToken(accessToken); if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) { @@ -427,7 +288,11 @@ public class MapView extends FrameLayout { , savedInstanceState.getInt(MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM)); mapboxMap.setDebugActive(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE)); - styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL); + + String styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL); + if (!TextUtils.isEmpty(styleUrl)) { + nativeMapView.setStyleUrl(savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL)); + } // User location try { @@ -462,11 +327,12 @@ public class MapView extends FrameLayout { addOnMapChangedListener(new OnMapChangedListener() { @Override public void onMapChanged(@MapChange int change) { + + // TODO extract logic into separate OnMapReady and Update Component if (change == DID_FINISH_LOADING_STYLE && initialLoad) { initialLoad = false; - iconManager.reloadIcons(); - annotationManager.reloadMarkers(); - annotationManager.adjustTopOffsetPixels(mapboxMap); + mapboxMap.getAnnotationManager().reloadMarkers(); + mapboxMap.getAnnotationManager().adjustTopOffsetPixels(mapboxMap); // Notify listeners the map is ready if (onMapReadyCallbackList.size() > 0) { @@ -484,7 +350,7 @@ public class MapView extends FrameLayout { } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) { mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation(); - compassView.update(getDirection()); + compassView.update(mapboxMap.getTransform().getBearing()); myLocationView.update(); mapboxMap.getMarkerViewManager().update(); @@ -517,7 +383,7 @@ public class MapView extends FrameLayout { outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true); outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, mapboxMap.getCameraPosition()); outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, mapboxMap.isDebugActive()); - outState.putString(MapboxConstants.STATE_STYLE_URL, styleUrl); + outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl()); outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, mapboxMap.isMyLocationEnabled()); // TrackingSettings @@ -579,9 +445,9 @@ public class MapView extends FrameLayout { nativeMapView.update(); myLocationView.onStart(); - // In case that no style was set or was loaded through MapboxMapOptions - if (!styleWasSet) { - setStyleUrl(styleUrl); + if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) { + // if user hasn't loaded a Style yet, load default for them instead + nativeMapView.setStyleUrl(Style.MAPBOX_STREETS); } } @@ -640,16 +506,63 @@ public class MapView extends FrameLayout { nativeMapView = null; } - void setFocalPoint(PointF focalPoint) { - if (focalPoint == null) { - // resetting focal point, - UiSettings uiSettings = mapboxMap.getUiSettings(); - // need to validate if we need to reset focal point with user provided one - if (uiSettings.getFocalPoint() != null) { - focalPoint = uiSettings.getFocalPoint(); + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(true); } } - this.focalPoint = focalPoint; + return mapGestureDetector.onTouchEvent(event) || super.onTouchEvent(event); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + return mapKeyListener.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + return mapKeyListener.onKeyLongPress(keyCode, event) || super.onKeyLongPress(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + return mapKeyListener.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); + } + + @Override + public boolean onTrackballEvent(MotionEvent event) { + return mapKeyListener.onTrackballEvent(event) || super.onTrackballEvent(event); + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + return mapGestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); + } + + @Override + public boolean onHoverEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + // Show the zoom controls + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(true); + } + return true; + + case MotionEvent.ACTION_HOVER_EXIT: + // Hide the zoom controls + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(false); + } + return true; + + default: + // We are not interested in this event + return false; + } } /** @@ -675,179 +588,6 @@ public class MapView extends FrameLayout { }); } - // - // LatLng / CenterCoordinate - // - - LatLng getLatLng() { - return nativeMapView.getLatLng(); - } - - // - // Pitch / Tilt - // - - double getTilt() { - return nativeMapView.getPitch(); - } - - void setTilt(Double pitch) { - mapboxMap.getMarkerViewManager().setTilt(pitch.floatValue()); - myLocationView.setTilt(pitch); - nativeMapView.setPitch(pitch, 0); - } - - // - // Center coordinate - // - - LatLng getCenterCoordinate() { - return nativeMapView.getLatLng(); - } - - void setCenterCoordinate(LatLng centerCoordinate) { - nativeMapView.setLatLng(centerCoordinate); - } - - // - // Direction - // - - double getDirection() { - if (destroyed) { - return 0; - } - - return convertNativeBearing(nativeMapView.getBearing()); - } - - void setDirection(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) double direction) { - if (destroyed) { - return; - } - setDirection(direction, false); - } - - void setDirection(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION) double direction, boolean animated) { - if (destroyed) { - return; - } - long duration = animated ? MapboxConstants.ANIMATION_DURATION : 0; - mapboxMap.cancelTransitions(); - // Out of range directions are normalised in setBearing - nativeMapView.setBearing(-direction, duration); - } - - void resetNorth() { - if (destroyed) { - return; - } - myLocationView.setBearing(0); - mapboxMap.cancelTransitions(); - nativeMapView.resetNorth(); - } - - // - // Content padding - // - - int getContentPaddingLeft() { - return contentPaddingLeft; - } - - int getContentPaddingTop() { - return contentPaddingTop; - } - - int getContentPaddingRight() { - return contentPaddingRight; - } - - int getContentPaddingBottom() { - return contentPaddingBottom; - } - - // - // Zoom - // - - double getZoom() { - if (destroyed) { - return 0; - } - return nativeMapView.getZoom(); - } - - void setMinZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) { - if (destroyed) { - return; - } - nativeMapView.setMinZoom(minZoom); - } - - double getMinZoom() { - if (destroyed) { - return 0; - } - return nativeMapView.getMinZoom(); - } - - void setMaxZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) { - if (destroyed) { - return; - } - nativeMapView.setMaxZoom(maxZoom); - } - - double getMaxZoom() { - if (destroyed) { - return 0; - } - return nativeMapView.getMaxZoom(); - } - - // Zoom in or out - private void zoom(boolean zoomIn) { - zoom(zoomIn, -1.0f, -1.0f); - } - - private void zoom(boolean zoomIn, float x, float y) { - // Cancel any animation - 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); - } - } - - // - // Debug - // - - boolean isDebugActive() { - return !destroyed && nativeMapView.getDebug(); - } - - void setDebugActive(boolean debugActive) { - if (destroyed) { - return; - } - nativeMapView.setDebug(debugActive); - } - - void cycleDebugOptions() { - if (destroyed) { - return; - } - nativeMapView.cycleDebugOptions(); - } - - // - // Styling - // - /** * <p> * Loads a new map style from the specified URL. @@ -886,57 +626,9 @@ public class MapView extends FrameLayout { setAccessToken(MapboxAccountManager.getInstance().getAccessToken()); } - styleUrl = url; nativeMapView.setStyleUrl(url); - styleWasSet = true; - } - - /** - * <p> - * Loads a new map style from the specified bundled style. - * </p> - * <p> - * This method is asynchronous and will return immediately before the style finishes loading. - * If you wish to wait for the map to finish loading listen for the {@link MapView#DID_FINISH_LOADING_MAP} event. - * </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. - * - * @param style The bundled style. Accepts one of the values from {@link Style}. - * @see Style - */ - @UiThread - public void setStyle(@Style.StyleUrl String style) { - setStyleUrl(style); - } - - /** - * <p> - * Returns the map style currently displayed in the map view. - * </p> - * If the default style is currently displayed, a URL will be returned instead of null. - * - * @return The URL of the map style. - */ - @UiThread - @NonNull - public String getStyleUrl() { - return styleUrl; } - // - // API Base URL - // - - @UiThread - void setApiBaseUrl(@NonNull String baseUrl) { - nativeMapView.setApiBaseUrl(baseUrl); - } - - // - // Access token - // - /** * <p> * DEPRECATED @see MapboxAccountManager#start(String) @@ -989,78 +681,6 @@ public class MapView extends FrameLayout { } // - // Projection - // - - /* - * Internal use only, use Projection#fromScreenLocation instead - */ - LatLng fromNativeScreenLocation(@NonNull PointF point) { - if (destroyed) { - return new LatLng(); - } - return nativeMapView.latLngForPixel(point); - } - - /* - * Internal use only, use Projection#toScreenLocation instead. - */ - PointF toNativeScreenLocation(@NonNull LatLng location) { - if (destroyed || location == null) { - return new PointF(); - } - return nativeMapView.pixelForLatLng(location); - } - - /** - * @return the ViewGroup containing the marker views - */ - public ViewGroup getMarkerViewContainer() { - return markerViewContainer; - } - - void setContentPadding(int left, int top, int right, int bottom) { - if (destroyed) { - return; - } - -// if (left == contentPaddingLeft && top == contentPaddingTop && right == contentPaddingRight && bottom == contentPaddingBottom) { -// return; -// } - - contentPaddingLeft = left; - contentPaddingTop = top; - contentPaddingRight = right; - contentPaddingBottom = bottom; - - int[] userLocationViewPadding = mapboxMap.getMyLocationViewSettings().getPadding(); - left += userLocationViewPadding[0]; - top += userLocationViewPadding[1]; - right += userLocationViewPadding[2]; - bottom += userLocationViewPadding[3]; - - nativeMapView.setContentPadding(top / screenDensity, left / screenDensity, bottom / screenDensity, right / screenDensity); - } - - public void invalidateContentPadding() { - setContentPadding(contentPaddingLeft, contentPaddingTop, contentPaddingRight, contentPaddingBottom); - - if (!mapboxMap.getTrackingSettings().isLocationTrackingDisabled()) { - setFocalPoint(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY())); - } else { - setFocalPoint(null); - } - } - - double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) double latitude) { - if (destroyed) { - return 0; - } - - return nativeMapView.getMetersPerPixelAtLatitude(latitude, getZoom()) / screenDensity; - } - - // // Rendering // @@ -1095,16 +715,8 @@ public class MapView extends FrameLayout { } if (!isInEditMode()) { - nativeMapView.resizeView((int) (width / screenDensity), (int) (height / screenDensity)); - } - } - - double getScale() { - if (destroyed) { - return 0; + nativeMapView.resizeView(width, height); } - - return nativeMapView.getScale(); } private class SurfaceCallback implements SurfaceHolder.Callback { @@ -1181,7 +793,8 @@ public class MapView extends FrameLayout { if (destroyed) { return; } - compassView.update(getDirection()); + // TODO move to transform. java + compassView.update(mapboxMap.getTransform().getBearing()); myLocationView.update(); mapboxMap.getMarkerViewManager().update(); @@ -1191,52 +804,6 @@ public class MapView extends FrameLayout { } } - void updateCameraPosition(@NonNull CameraPosition position) { - myLocationView.setCameraPosition(position); - mapboxMap.getMarkerViewManager().setTilt((float) position.tilt); - } - - double getBearing() { - if (destroyed) { - return 0; - } - - double direction = -nativeMapView.getBearing(); - - while (direction > 360) { - direction -= 360; - } - while (direction < 0) { - direction += 360; - } - - return direction; - } - - void setBearing(double bearing) { - if (destroyed) { - return; - } - myLocationView.setBearing(bearing); - nativeMapView.setBearing(bearing); - } - - void setBearing(double bearing, long duration) { - if (destroyed) { - return; - } - myLocationView.setBearing(bearing); - nativeMapView.setBearing(bearing, duration); - } - - void setBearing(double bearing, float focalX, float focalY) { - if (destroyed) { - return; - } - myLocationView.setBearing(bearing); - nativeMapView.setBearing(bearing, focalX, focalY); - } - // // View events // @@ -1267,898 +834,8 @@ public class MapView extends FrameLayout { return; } - // Required by ZoomButtonController (from Android SDK documentation) - if (visibility == View.VISIBLE) { - if (mapboxMap != null && mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(true); - } - } else { - if (mapboxMap != null && mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(false); - } - } - } - - // - // Touch events - // - - /** - * Helper method for tracking gesture events - * - * @param gestureId Type of Gesture See {@see MapboxEvent#GESTURE_SINGLETAP MapboxEvent#GESTURE_DOUBLETAP MapboxEvent#GESTURE_TWO_FINGER_SINGLETAP MapboxEvent#GESTURE_QUICK_ZOOM MapboxEvent#GESTURE_PAN_START MapboxEvent#GESTURE_PINCH_START MapboxEvent#GESTURE_ROTATION_START MapboxEvent#GESTURE_PITCH_START} - * @param xCoordinate Original x screen coordinate at start of gesture - * @param yCoordinate Original y screen cooridnate at start of gesture - */ - private void trackGestureEvent(@NonNull String gestureId, float xCoordinate, float yCoordinate) { - LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate)); - - // NaN and Infinite checks to prevent JSON errors at send to server time - if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) { - Timber.d("trackGestureEvent() has a NaN lat or lon. Returning."); - return; - } - - if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) { - Timber.d("trackGestureEvent() has an Infinite lat or lon. Returning."); - return; - } - - Hashtable<String, Object> evt = new Hashtable<>(); - evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK); - evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate()); - evt.put(MapboxEvent.KEY_GESTURE_ID, gestureId); - evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude()); - evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude()); - evt.put(MapboxEvent.KEY_ZOOM, mapboxMap.getCameraPosition().zoom); - - MapboxEventManager.getMapboxEventManager().pushEvent(evt); - } - - /** - * Helper method for tracking DragEnd gesture event - * See {@see MapboxEvent#TYPE_MAP_DRAGEND} - * - * @param xCoordinate Original x screen coordinate at end of drag - * @param yCoordinate Orginal y screen coordinate at end of drag - */ - private void trackGestureDragEndEvent(float xCoordinate, float yCoordinate) { - LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate)); - - // NaN and Infinite checks to prevent JSON errors at send to server time - if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) { - Timber.d("trackGestureDragEndEvent() has a NaN lat or lon. Returning."); - return; - } - - if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) { - Timber.d("trackGestureDragEndEvent() has an Infinite lat or lon. Returning."); - return; - } - - Hashtable<String, Object> evt = new Hashtable<>(); - evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_DRAGEND); - evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate()); - evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude()); - evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude()); - evt.put(MapboxEvent.KEY_ZOOM, mapboxMap.getCameraPosition().zoom); - - MapboxEventManager.getMapboxEventManager().pushEvent(evt); - } - - // Called when user touches the screen, all positions are absolute - @Override - public boolean onTouchEvent(@NonNull MotionEvent event) { - // Check and ignore non touch or left clicks - if (destroyed) { - return super.onTouchEvent(event); - } - - if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { - return false; - } - - // Check two finger gestures first - rotateGestureDetector.onTouchEvent(event); - scaleGestureDetector.onTouchEvent(event); - shoveGestureDetector.onTouchEvent(event); - - // Handle two finger tap - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - // First pointer down - nativeMapView.setGestureInProgress(true); - break; - - case MotionEvent.ACTION_POINTER_DOWN: - // Second pointer down - twoTap = event.getPointerCount() == 2 - && mapboxMap.getUiSettings().isZoomGesturesEnabled(); - if (twoTap) { - // Confirmed 2nd Finger Down - trackGestureEvent(MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY()); - } - break; - - case MotionEvent.ACTION_POINTER_UP: - // Second pointer up - break; - - case MotionEvent.ACTION_UP: - // First pointer up - long tapInterval = event.getEventTime() - event.getDownTime(); - boolean isTap = tapInterval <= ViewConfiguration.getTapTimeout(); - boolean inProgress = rotateGestureDetector.isInProgress() - || scaleGestureDetector.isInProgress() - || shoveGestureDetector.isInProgress(); - - if (twoTap && isTap && !inProgress) { - if (focalPoint != null) { - zoom(false, focalPoint.x, focalPoint.y); - } else { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - zoom(false, focalPoint.x, focalPoint.y); - } - twoTap = false; - return true; - } - - // Scroll / Pan Has Stopped - if (scrollInProgress) { - trackGestureDragEndEvent(event.getX(), event.getY()); - scrollInProgress = false; - } - - twoTap = false; - nativeMapView.setGestureInProgress(false); - break; - - case MotionEvent.ACTION_CANCEL: - twoTap = false; - nativeMapView.setGestureInProgress(false); - break; - } - - boolean retVal = gestureDetector.onTouchEvent(event); - return retVal || super.onTouchEvent(event); - } - - // This class handles one finger gestures - private class GestureListener extends GestureDetector.SimpleOnGestureListener { - - // Must always return true otherwise all events are ignored - @Override - @SuppressLint("ResourceType") - public boolean onDown(MotionEvent event) { - // Show the zoom controls - if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(true); - } - return true; - } - - // Called for double taps - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - if (destroyed || !mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - switch (e.getAction()) { - case MotionEvent.ACTION_DOWN: - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - if (quickZoom) { - // insert here? - quickZoom = false; - break; - } - - // Single finger double tap - if (focalPoint != null) { - // User provided focal point - zoom(true, focalPoint.x, focalPoint.y); - } else { - // Zoom in on gesture - zoom(true, e.getX(), e.getY()); - } - break; - } - - trackGestureEvent(MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY()); - - return true; - } - - @Override - public boolean onSingleTapUp(MotionEvent motionEvent) { - if (destroyed) { - return false; - } - // Cancel any animation - mapboxMap.cancelTransitions(); - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent motionEvent) { - List<Marker> selectedMarkers = mapboxMap.getSelectedMarkers(); - - PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY()); - float toleranceSides = 4 * screenDensity; - float toleranceTopBottom = 10 * screenDensity; - - RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides, - tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom, - tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides, - tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom); - - List<Marker> nearbyMarkers = annotationManager.getMarkersInRect(tapRect); - long newSelectedMarkerId = -1; - - if (nearbyMarkers != null && nearbyMarkers.size() > 0) { - Collections.sort(nearbyMarkers); - for (Marker nearbyMarker : nearbyMarkers) { - boolean found = false; - for (Marker selectedMarker : selectedMarkers) { - if (selectedMarker.equals(nearbyMarker)) { - found = true; - } - } - if (!found) { - newSelectedMarkerId = nearbyMarker.getId(); - break; - } - } - } - - if (newSelectedMarkerId >= 0) { - List<Annotation> annotations = mapboxMap.getAnnotations(); - int count = annotations.size(); - for (int i = 0; i < count; i++) { - Annotation annotation = annotations.get(i); - if (annotation instanceof Marker) { - if (annotation.getId() == newSelectedMarkerId) { - if (selectedMarkers.isEmpty() || !selectedMarkers.contains(annotation)) { - if (!(annotation instanceof MarkerView)) { - mapboxMap.selectMarker((Marker) annotation); - } else { - mapboxMap.getMarkerViewManager().onClickMarkerView((MarkerView) annotation); - } - } - break; - } - } - } - } else { - if (mapboxMap.getUiSettings().isDeselectMarkersOnTap()) { - // deselect any selected marker - mapboxMap.deselectMarkers(); - } - - // notify app of map click - MapboxMap.OnMapClickListener listener = mapboxMap.getOnMapClickListener(); - if (listener != null) { - LatLng point = projection.fromScreenLocation(tapPoint); - listener.onMapClick(point); - } - } - - trackGestureEvent(MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY()); - return true; - } - - // Called for a long press - @Override - public void onLongPress(MotionEvent motionEvent) { - MapboxMap.OnMapLongClickListener listener = mapboxMap.getOnMapLongClickListener(); - if (listener != null && !quickZoom) { - LatLng point = projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY())); - listener.onMapLongClick(point); - } - } - - // Called for flings - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (destroyed || !mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false); - - double decelerationRate = 1; - - // Cancel any animation - mapboxMap.cancelTransitions(); - - double offsetX = velocityX * decelerationRate / 4 / screenDensity; - double offsetY = velocityY * decelerationRate / 4 / screenDensity; - - nativeMapView.setGestureInProgress(true); - nativeMapView.moveBy(offsetX, offsetY, (long) (decelerationRate * 1000.0f)); - nativeMapView.setGestureInProgress(false); - - MapboxMap.OnFlingListener listener = mapboxMap.getOnFlingListener(); - if (listener != null) { - listener.onFling(); - } - - trackGestureEvent(MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY()); - return true; - } - - // Called for drags - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (!scrollInProgress) { - scrollInProgress = true; - } - if (destroyed || !mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - if (dragStarted) { - return false; - } - - requestDisallowInterceptTouchEvent(true); - - // reset tracking if needed - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false); - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Scroll the map - nativeMapView.moveBy(-distanceX / screenDensity, -distanceY / screenDensity); - - MapboxMap.OnScrollListener listener = mapboxMap.getOnScrollListener(); - if (listener != null) { - listener.onScroll(); - } - return true; - } - } - - // This class handles two finger gestures and double-tap drag gestures - private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - - long beginTime = 0; - float scaleFactor = 1.0f; - - // Called when two fingers first touch the screen - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - if (destroyed || !mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - beginTime = detector.getEventTime(); - trackGestureEvent(MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY()); - return true; - } - - // Called when fingers leave screen - @Override - public void onScaleEnd(ScaleGestureDetector detector) { - beginTime = 0; - scaleFactor = 1.0f; - zoomStarted = false; - } - - // Called each time a finger moves - // Called for pinch zooms and quickzooms/quickscales - @Override - public boolean onScale(ScaleGestureDetector detector) { - UiSettings uiSettings = mapboxMap.getUiSettings(); - if (destroyed || !uiSettings.isZoomGesturesEnabled()) { - return super.onScale(detector); - } - - // If scale is large enough ignore a tap - scaleFactor *= detector.getScaleFactor(); - if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) { - zoomStarted = true; - } - - // Ignore short touches in case it is a tap - // Also ignore small scales - long time = detector.getEventTime(); - long interval = time - beginTime; - if (!zoomStarted && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } - - if (!zoomStarted) { - return false; - } - - if (dragStarted) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Gesture is a quickzoom if there aren't two fingers - quickZoom = !twoTap; - - // make an assumption here; if the zoom center is specified by the gesture, it's NOT going - // to be in the center of the map. Therefore the zoom will translate the map center, so tracking - // should be disabled. - - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(!quickZoom, false); - // Scale the map - if (focalPoint != null) { - // arround user provided focal point - nativeMapView.scaleBy(detector.getScaleFactor(), focalPoint.x / screenDensity, focalPoint.y / screenDensity); - } else if (quickZoom) { - // around center map - nativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / screenDensity, (getHeight() / 2) / screenDensity); - } else { - // around gesture - nativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / screenDensity, detector.getFocusY() / screenDensity); - } - - return true; - } - } - - // This class handles two finger rotate gestures - private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - - long beginTime = 0; - float totalAngle = 0.0f; - boolean started = false; - - // Called when two fingers first touch the screen - @Override - public boolean onRotateBegin(RotateGestureDetector detector) { - if (destroyed || !mapboxMap.getTrackingSettings().isRotateGestureCurrentlyEnabled()) { - return false; - } - - beginTime = detector.getEventTime(); - trackGestureEvent(MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY()); - return true; - } - - // Called when the fingers leave the screen - @Override - public void onRotateEnd(RotateGestureDetector detector) { - beginTime = 0; - totalAngle = 0.0f; - started = false; - } - - // Called each time one of the two fingers moves - // Called for rotation - @Override - public boolean onRotate(RotateGestureDetector detector) { - if (destroyed || !mapboxMap.getTrackingSettings().isRotateGestureCurrentlyEnabled() || dragStarted) { - return false; - } - - // If rotate is large enough ignore a tap - // Also is zoom already started, don't rotate - totalAngle += detector.getRotationDegreesDelta(); - if (!zoomStarted && ((totalAngle > 20.0f) || (totalAngle < -20.0f))) { - started = true; - } - - // Ignore short touches in case it is a tap - // Also ignore small rotate - long time = detector.getEventTime(); - long interval = time - beginTime; - if (!started && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } - - if (!started) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // rotation constitutes translation of anything except the center of - // rotation, so cancel both location and bearing tracking if required - - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, true); - - // Get rotate value - double bearing = nativeMapView.getBearing(); - bearing += detector.getRotationDegreesDelta(); - - // Rotate the map - if (focalPoint != null) { - // User provided focal point - setBearing(bearing, focalPoint.x / screenDensity, focalPoint.y / screenDensity); - } else { - // around gesture - setBearing(bearing, detector.getFocusX() / screenDensity, detector.getFocusY() / screenDensity); - } - return true; - } - } - - // This class handles a vertical two-finger shove. (If you place two fingers on screen with - // less than a 20 degree angle between them, this will detect movement on the Y-axis.) - private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { - - long beginTime = 0; - float totalDelta = 0.0f; - boolean started = false; - - @Override - public boolean onShoveBegin(ShoveGestureDetector detector) { - if (!mapboxMap.getUiSettings().isTiltGesturesEnabled()) { - return false; - } - - beginTime = detector.getEventTime(); - trackGestureEvent(MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY()); - return true; - } - - @Override - public void onShoveEnd(ShoveGestureDetector detector) { - beginTime = 0; - totalDelta = 0.0f; - started = false; - dragStarted = false; - } - - @Override - public boolean onShove(ShoveGestureDetector detector) { - if (destroyed || !mapboxMap.getUiSettings().isTiltGesturesEnabled()) { - return false; - } - - // If tilt is large enough ignore a tap - // Also if zoom already started, don't tilt - totalDelta += detector.getShovePixelsDelta(); - if (!zoomStarted && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) { - started = true; - } - - // Ignore short touches in case it is a tap - // Also ignore small tilt - long time = detector.getEventTime(); - long interval = time - beginTime; - if (!started && (interval <= ViewConfiguration.getTapTimeout())) { - return false; - } - - if (!started) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Get tilt value (scale and clamp) - double pitch = getTilt(); - pitch -= 0.1 * detector.getShovePixelsDelta(); - pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); - - // Tilt the map - mapboxMap.setTilt(pitch); - - dragStarted = true; - - return true; - } - } - - // This class handles input events from the zoom control buttons - // Zoom controls allow single touch only devices to zoom in and out - private class OnZoomListener implements ZoomButtonsController.OnZoomListener { - - // Not used - @Override - public void onVisibilityChanged(boolean visible) { - // Ignore - } - - // Called when user pushes a zoom button - @Override - public void onZoom(boolean zoomIn) { - if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return; - } - zoom(zoomIn); - } - } - - // - // Input events - // - - // Called when the user presses a key, also called for repeating keys held - // down - @Override - public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { - if (destroyed) { - return super.onKeyDown(keyCode, event); - } - - // If the user has held the scroll key down for a while then accelerate - // the scroll speed - double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; - - // Check which key was pressed via hardware/real key code - switch (keyCode) { - // Tell the system to track these keys for long presses on - // onKeyLongPress is fired - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - event.startTracking(); - return true; - - case KeyEvent.KEYCODE_DPAD_LEFT: - if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Move left - nativeMapView.moveBy(scrollDist / screenDensity, 0.0 / screenDensity); - return true; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Move right - nativeMapView.moveBy(-scrollDist / screenDensity, 0.0 / screenDensity); - return true; - - case KeyEvent.KEYCODE_DPAD_UP: - if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Move up - nativeMapView.moveBy(0.0 / screenDensity, scrollDist / screenDensity); - return true; - - case KeyEvent.KEYCODE_DPAD_DOWN: - if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Move down - nativeMapView.moveBy(0.0 / screenDensity, -scrollDist / screenDensity); - return true; - - default: - // We are not interested in this key - return super.onKeyUp(keyCode, event); - } - } - - // Called when the user long presses a key that is being tracked - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - // Check which key was pressed via hardware/real key code - switch (keyCode) { - // Tell the system to track these keys for long presses on - // onKeyLongPress is fired - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - // Zoom out - zoom(false); - return true; - - default: - // We are not interested in this key - return super.onKeyUp(keyCode, event); - } - } - - // Called when the user releases a key - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - // Check if the key action was canceled (used for virtual keyboards) - if (event.isCanceled()) { - return super.onKeyUp(keyCode, event); - } - - // Check which key was pressed via hardware/real key code - // Note if keyboard does not have physical key (ie primary non-shifted - // key) then it will not appear here - // Must use the key character map as physical to character is not - // fixed/guaranteed - switch (keyCode) { - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - // Zoom in - zoom(true); - return true; - } - - // We are not interested in this key - return super.onKeyUp(keyCode, event); - } - - // Called for trackball events, all motions are relative in device specific - // units - @Override - public boolean onTrackballEvent(MotionEvent event) { - if (destroyed) { - return false; - } - // Choose the action - switch (event.getActionMasked()) { - // The trackball was rotated - case MotionEvent.ACTION_MOVE: - if (!mapboxMap.getTrackingSettings().isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Scroll the map - nativeMapView.moveBy(-10.0 * event.getX() / screenDensity, -10.0 * event.getY() / screenDensity); - return true; - - // Trackball was pushed in so start tracking and tell system we are - // interested - // We will then get the up action - case MotionEvent.ACTION_DOWN: - // Set up a delayed callback to check if trackball is still - // After waiting the system long press time out - if (currentTrackballLongPressTimeOut != null) { - currentTrackballLongPressTimeOut.cancel(); - currentTrackballLongPressTimeOut = null; - } - currentTrackballLongPressTimeOut = new TrackballLongPressTimeOut(); - postDelayed(currentTrackballLongPressTimeOut, - ViewConfiguration.getLongPressTimeout()); - return true; - - // Trackball was released - case MotionEvent.ACTION_UP: - if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - // Only handle if we have not already long pressed - if (currentTrackballLongPressTimeOut != null) { - // Zoom in - zoom(true); - } - return true; - - // Trackball was cancelled - case MotionEvent.ACTION_CANCEL: - if (currentTrackballLongPressTimeOut != null) { - currentTrackballLongPressTimeOut.cancel(); - currentTrackballLongPressTimeOut = null; - } - return true; - - default: - // We are not interested in this event - return super.onTrackballEvent(event); - } - } - - // This class implements the trackball long press time out callback - private class TrackballLongPressTimeOut implements Runnable { - - // Track if we have been cancelled - private boolean cancelled; - - TrackballLongPressTimeOut() { - cancelled = false; - } - - // Cancel the timeout - public void cancel() { - cancelled = true; - } - - // Called when long press time out expires - @Override - public void run() { - // Check if the trackball is still pressed - if (!cancelled) { - // Zoom out - zoom(false); - - // Ensure the up action is not run - currentTrackballLongPressTimeOut = null; - } - } - } - - // Called for events that don't fit the other handlers - // such as mouse scroll events, mouse moves, joystick, trackpad - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - if (destroyed) { - return false; - } - // Mouse events - //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18 - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { - // Choose the action - switch (event.getActionMasked()) { - // Mouse scrolls - case MotionEvent.ACTION_SCROLL: - if (!mapboxMap.getUiSettings().isZoomGesturesEnabled()) { - return false; - } - - // Cancel any animation - mapboxMap.cancelTransitions(); - - // Get the vertical scroll amount, one click = 1 - float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - - // Scale the map by the appropriate power of two factor - nativeMapView.scaleBy(Math.pow(2.0, scrollDist), event.getX() / screenDensity, event.getY() / screenDensity); - - return true; - - default: - // We are not interested in this event - return super.onGenericMotionEvent(event); - } - } - - // We are not interested in this event - return super.onGenericMotionEvent(event); - } - - // Called when the mouse pointer enters or exits the view - // or when it fades in or out due to movement - @Override - public boolean onHoverEvent(@NonNull MotionEvent event) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_HOVER_ENTER: - case MotionEvent.ACTION_HOVER_MOVE: - // Show the zoom controls - if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(true); - } - return true; - - case MotionEvent.ACTION_HOVER_EXIT: - // Hide the zoom controls - if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(false); - } - return true; - - default: - // We are not interested in this event - return super.onHoverEvent(event); + if (mapboxMap != null && mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(visibility == View.VISIBLE); } } @@ -2230,133 +907,6 @@ public class MapView extends FrameLayout { nativeMapView.onMapChangedEventDispatch(mapChange); } - // - // User location - // - - void setMyLocationEnabled(boolean enabled) { - myLocationView.setEnabled(enabled); - } - - Location getMyLocation() { - return myLocationView.getLocation(); - } - - void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) { - if (listener != null) { - myLocationListener = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - if (listener != null) { - listener.onMyLocationChange(location); - } - } - }; - LocationServices.getLocationServices(getContext()).addLocationListener(myLocationListener); - } else { - LocationServices.getLocationServices(getContext()).removeLocationListener(myLocationListener); - myLocationListener = null; - } - } - - void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { - if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && !mapboxMap.isMyLocationEnabled()) { - mapboxMap.setMyLocationEnabled(true); - } - myLocationView.setMyLocationTrackingMode(myLocationTrackingMode); - - if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - setFocalPoint(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY())); - } else { - setFocalPoint(null); - } - - MapboxMap.OnMyLocationTrackingModeChangeListener listener = mapboxMap.getOnMyLocationTrackingModeChangeListener(); - if (listener != null) { - listener.onMyLocationTrackingModeChange(myLocationTrackingMode); - } - } - - void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { - if (myBearingTrackingMode != MyBearingTracking.NONE && !mapboxMap.isMyLocationEnabled()) { - mapboxMap.setMyLocationEnabled(true); - } - myLocationView.setMyBearingTrackingMode(myBearingTrackingMode); - MapboxMap.OnMyBearingTrackingModeChangeListener listener = mapboxMap.getOnMyBearingTrackingModeChangeListener(); - if (listener != null) { - listener.onMyBearingTrackingModeChange(myBearingTrackingMode); - } - } - - boolean isPermissionsAccepted() { - return (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) || - ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; - } - - // - // Compass - // - - void setCompassEnabled(boolean compassEnabled) { - compassView.setEnabled(compassEnabled); - } - - void setCompassGravity(int gravity) { - setWidgetGravity(compassView, gravity); - } - - void setCompassMargins(int left, int top, int right, int bottom) { - setWidgetMargins(compassView, left, top, right, bottom); - } - - void setCompassFadeFacingNorth(boolean compassFadeFacingNorth) { - compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth); - } - - // - // Logo - // - - void setLogoGravity(int gravity) { - setWidgetGravity(logoView, gravity); - } - - void setLogoMargins(int left, int top, int right, int bottom) { - setWidgetMargins(logoView, left, top, right, bottom); - } - - void setLogoEnabled(boolean visible) { - logoView.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - // - // Attribution - // - - void setAttributionGravity(int gravity) { - setWidgetGravity(attributionsView, gravity); - } - - void setAttributionMargins(int left, int top, int right, int bottom) { - setWidgetMargins(attributionsView, left, top, right, bottom); - } - - void setAttributionEnabled(int visibility) { - attributionsView.setVisibility(visibility); - } - - void setAtttibutionTintColor(int tintColor) { - // Check that the tint color being passed in isn't transparent. - if (Color.alpha(tintColor) == 0) { - ColorUtils.setTintList(attributionsView, ContextCompat.getColor(getContext(), R.color.mapbox_blue)); - } else { - ColorUtils.setTintList(attributionsView, tintColor); - } - } - - int getAttributionTintColor() { - return mapboxMap.getUiSettings().getAttributionTintColor(); - } /** * Sets a callback object which will be triggered when the {@link MapboxMap} instance is ready to be used. @@ -2382,14 +932,6 @@ public class MapView extends FrameLayout { this.mapboxMap = mapboxMap; } - MyLocationView getUserLocationView() { - return myLocationView; - } - - NativeMapView getNativeMapView() { - return nativeMapView; - } - // // Snapshot API // @@ -2437,26 +979,6 @@ public class MapView extends FrameLayout { } } - // - // View utility methods - // - - private void setWidgetGravity(@NonNull final View view, int gravity) { - LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); - layoutParams.gravity = gravity; - view.setLayoutParams(layoutParams); - } - - private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) { - LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); - left += contentPaddingLeft; - top += contentPaddingTop; - right += contentPaddingRight; - bottom += contentPaddingBottom; - layoutParams.setMargins(left, top, right, bottom); - view.setLayoutParams(layoutParams); - } - private static class AttributionOnClickListener implements View.OnClickListener, DialogInterface.OnClickListener { private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2; @@ -2511,16 +1033,16 @@ public class MapView extends FrameLayout { } }); - AlertDialog telemDialog = builder.show(); - telemDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(mapView.getAttributionTintColor()); - telemDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(mapView.getAttributionTintColor()); - telemDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(mapView.getAttributionTintColor()); + builder.show(); return; } String url = context.getResources().getStringArray(R.array.mapbox_attribution_links)[which]; if (which == ATTRIBUTION_INDEX_IMPROVE_THIS_MAP) { - LatLng latLng = mapView.getMapboxMap().getCameraPosition().target; - url = String.format(url, latLng.getLongitude(), latLng.getLatitude(), (int) mapView.getZoom()); + CameraPosition cameraPosition = mapView.getMapboxMap().getCameraPosition(); + if (cameraPosition != null) { + url = String.format(url, cameraPosition.target.getLongitude(), + cameraPosition.target.getLatitude(), (int) cameraPosition.zoom); + } } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); @@ -2767,4 +1289,66 @@ public class MapView extends FrameLayout { void onMapChanged(@MapChange int change); } + // This class handles input events from the zoom control buttons + // Zoom controls allow single touch only devices to zoom in and out + private class OnZoomListener implements ZoomButtonsController.OnZoomListener { + + private UiSettings uiSettings; + private Transform transform; + + OnZoomListener(MapboxMap mapboxMap) { + this.uiSettings = mapboxMap.getUiSettings(); + this.transform = mapboxMap.getTransform(); + } + + // Not used + @Override + public void onVisibilityChanged(boolean visible) { + // Ignore + } + + // Called when user pushes a zoom button + @Override + public void onZoom(boolean zoomIn) { + if (!uiSettings.isZoomGesturesEnabled()) { + return; + } + transform.zoom(zoomIn); + } + } + + private class FocalPointInvalidator implements FocalPointChangeListener { + + @Override + public void onFocalPointChanged(PointF pointF) { + mapGestureDetector.setFocalPoint(pointF); + } + } + + private class RegisterTouchListener implements MapboxMap.OnRegisterTouchListener { + + @Override + public void onRegisterMapClickListener(MapboxMap.OnMapClickListener listener) { + mapGestureDetector.setOnMapClickListener(listener); + } + + @Override + public void onRegisterMapLongClickListener(MapboxMap.OnMapLongClickListener listener) { + mapGestureDetector.setOnMapLongClickListener(listener); + } + + @Override + public void onRegisterScrollListener(MapboxMap.OnScrollListener listener) { + mapGestureDetector.setOnScrollListener(listener); + } + + @Override + public void onRegisterFlingListener(MapboxMap.OnFlingListener listener) { + mapGestureDetector.setOnFlingListener(listener); + } + } + + NativeMapView getNativeMapView() { + return nativeMapView; + } } 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 fa856a7aa7..2923fa2e52 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1,20 +1,27 @@ package com.mapbox.mapboxsdk.maps; import android.content.Context; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.RectF; import android.location.Location; +import android.os.Handler; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v4.util.Pools; + import timber.log.Timber; + +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import android.widget.ZoomButtonsController; import com.mapbox.mapboxsdk.MapboxAccountManager; +import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; @@ -40,6 +47,7 @@ import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException; import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException; import com.mapbox.mapboxsdk.style.sources.Source; +import com.mapbox.mapboxsdk.utils.ColorUtils; import com.mapbox.services.commons.geojson.Feature; import java.lang.reflect.ParameterizedType; @@ -54,46 +62,134 @@ import java.util.List; * Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread. * </p> */ -public class MapboxMap { - - private MapView mapView; - private UiSettings uiSettings; - private TrackingSettings trackingSettings; - private MyLocationViewSettings myLocationViewSettings; - private Projection projection; - private Transform transform; - private boolean myLocationEnabled; +public final class MapboxMap { - private MapboxMap.OnMapClickListener onMapClickListener; - private MapboxMap.OnMapLongClickListener onMapLongClickListener; + private final NativeMapView nativeMapView; + private final UiSettings uiSettings; + private final TrackingSettings trackingSettings; + private final Projection projection; + private final Transform transform; + private final AnnotationManager annotationManager; + private final MyLocationViewSettings myLocationViewSettings; + private final OnRegisterTouchListener onRegisterTouchListener; - - private MapboxMap.OnFlingListener onFlingListener; - private MapboxMap.OnScrollListener onScrollListener; - private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; - private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; private MapboxMap.OnFpsChangedListener onFpsChangedListener; - private AnnotationManager annotationManager; - private InfoWindowManager infoWindowManager; + private boolean myLocationEnabled; private double maxZoomLevel = -1; private double minZoomLevel = -1; - MapboxMap(@NonNull MapView mapView, IconManager iconManager) { - this.mapView = mapView; - 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()); + MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking, MyLocationViewSettings myLocationView, + Projection projection, OnRegisterTouchListener listener, AnnotationManager annotations) { + this.nativeMapView = map; + this.uiSettings = ui; + this.trackingSettings = tracking; + this.projection = projection; + this.myLocationViewSettings = myLocationView; + this.annotationManager = annotations.bind(this); + this.transform = transform; + this.onRegisterTouchListener = listener; + } + + void initialise(Context context, MapboxMapOptions options) { + // TODO migrate code from this method to the classes they impact themselves + setDebugActive(options.getDebugActive()); + + CameraPosition position = options.getCamera(); + if (position != null && !position.equals(CameraPosition.DEFAULT)) { + transform.moveCamera(this, CameraUpdateFactory.newCameraPosition(position), null); + myLocationViewSettings.setTilt(position.tilt); + } + + // api base url + String apiBaseUrl = options.getApiBaseUrl(); + if (!TextUtils.isEmpty(apiBaseUrl)) { + nativeMapView.setApiBaseUrl(apiBaseUrl); + } + + // access token + String accessToken = options.getAccessToken(); + if (!TextUtils.isEmpty(accessToken)) { + nativeMapView.setAccessToken(accessToken); + }else{ + nativeMapView.setAccessToken(MapboxAccountManager.getInstance().getAccessToken()); + } + + // style url + String style = options.getStyle(); + if (!TextUtils.isEmpty(style)) { + nativeMapView.setStyleUrl(style); + } + + // MyLocationView + myLocationViewSettings.setForegroundDrawable( + options.getMyLocationForegroundDrawable(), options.getMyLocationForegroundBearingDrawable()); + myLocationViewSettings.setForegroundTintColor(options.getMyLocationForegroundTintColor()); + myLocationViewSettings.setBackgroundDrawable( + options.getMyLocationBackgroundDrawable(), options.getMyLocationBackgroundPadding()); + myLocationViewSettings.setBackgroundTintColor(options.getMyLocationBackgroundTintColor()); + myLocationViewSettings.setAccuracyAlpha(options.getMyLocationAccuracyAlpha()); + myLocationViewSettings.setAccuracyTintColor(options.getMyLocationAccuracyTintColor()); + setMyLocationEnabled(options.getLocationEnabled()); + + // Enable gestures + uiSettings.setZoomGesturesEnabled(options.getZoomGesturesEnabled()); + uiSettings.setZoomGestureChangeAllowed(options.getZoomGesturesEnabled()); + uiSettings.setScrollGesturesEnabled(options.getScrollGesturesEnabled()); + uiSettings.setScrollGestureChangeAllowed(options.getScrollGesturesEnabled()); + uiSettings.setRotateGesturesEnabled(options.getRotateGesturesEnabled()); + uiSettings.setRotateGestureChangeAllowed(options.getRotateGesturesEnabled()); + uiSettings.setTiltGesturesEnabled(options.getTiltGesturesEnabled()); + uiSettings.setTiltGestureChangeAllowed(options.getTiltGesturesEnabled()); + + // Ui Controls + uiSettings.setZoomControlsEnabled(options.getZoomControlsEnabled()); + + // Zoom + setMaxZoom(options.getMaxZoom()); + setMinZoom(options.getMinZoom()); + + Resources resources = context.getResources(); + + // Compass + uiSettings.setCompassEnabled(options.getCompassEnabled()); + uiSettings.setCompassGravity(options.getCompassGravity()); + int[] compassMargins = options.getCompassMargins(); + if (compassMargins != null) { + uiSettings.setCompassMargins(compassMargins[0], compassMargins[1], compassMargins[2], compassMargins[3]); + } else { + int tenDp = (int) resources.getDimension(R.dimen.mapbox_ten_dp); + uiSettings.setCompassMargins(tenDp, tenDp, tenDp, tenDp); } + uiSettings.setCompassFadeFacingNorth(options.getCompassFadeFacingNorth()); + + // Logo + uiSettings.setLogoEnabled(options.getLogoEnabled()); + uiSettings.setLogoGravity(options.getLogoGravity()); + int[] logoMargins = options.getLogoMargins(); + if (logoMargins != null) { + uiSettings.setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]); + } else { + int sixteenDp = (int) resources.getDimension(R.dimen.mapbox_sixteen_dp); + uiSettings.setLogoMargins(sixteenDp, sixteenDp, sixteenDp, sixteenDp); + } + + // Attribution + uiSettings.setAttributionEnabled(options.getAttributionEnabled()); + uiSettings.setAttributionGravity(options.getAttributionGravity()); + int[] attributionMargins = options.getAttributionMargins(); + if (attributionMargins != null) { + uiSettings.setAttributionMargins(attributionMargins[0], attributionMargins[1], attributionMargins[2], attributionMargins[3]); + } else { + int sevenDp = (int) resources.getDimension(R.dimen.mapbox_seven_dp); + int seventySixDp = (int) resources.getDimension(R.dimen.mapbox_seventy_six_dp); + uiSettings.setAttributionMargins(seventySixDp, sevenDp, sevenDp, sevenDp); + } + + int attributionTintColor = options.getAttributionTintColor(); + uiSettings.setAttributionTintColor(attributionTintColor != -1 + ? attributionTintColor : ColorUtils.getPrimaryColor(context)); } // Style @@ -101,7 +197,7 @@ public class MapboxMap { @Nullable @UiThread public Layer getLayer(@NonNull String layerId) { - return getMapView().getNativeMapView().getLayer(layerId); + return nativeMapView.getLayer(layerId); } /** @@ -116,7 +212,7 @@ public class MapboxMap { public <T extends Layer> T getLayerAs(@NonNull String layerId) { try { //noinspection unchecked - return (T) getMapView().getNativeMapView().getLayer(layerId); + return (T) nativeMapView.getLayer(layerId); } catch (ClassCastException e) { Timber.e(String.format("Layer: %s is a different type: %s", layerId, e.getMessage())); return null; @@ -141,7 +237,7 @@ public class MapboxMap { */ @UiThread public void addLayer(@NonNull Layer layer, String before) { - getMapView().getNativeMapView().addLayer(layer, before); + nativeMapView.addLayer(layer, before); } /** @@ -152,7 +248,7 @@ public class MapboxMap { */ @UiThread public void removeLayer(@NonNull String layerId) throws NoSuchLayerException { - getMapView().getNativeMapView().removeLayer(layerId); + nativeMapView.removeLayer(layerId); } /** @@ -163,13 +259,13 @@ public class MapboxMap { */ @UiThread public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException { - getMapView().getNativeMapView().removeLayer(layer); + nativeMapView.removeLayer(layer); } @Nullable @UiThread public Source getSource(@NonNull String sourceId) { - return getMapView().getNativeMapView().getSource(sourceId); + return nativeMapView.getSource(sourceId); } /** @@ -184,7 +280,7 @@ public class MapboxMap { public <T extends Source> T getSourceAs(@NonNull String sourceId) { try { //noinspection unchecked - return (T) getMapView().getNativeMapView().getSource(sourceId); + return (T) nativeMapView.getSource(sourceId); } catch (ClassCastException e) { Timber.e(String.format("Source: %s is a different type: %s", sourceId, e.getMessage())); return null; @@ -198,7 +294,7 @@ public class MapboxMap { */ @UiThread public void addSource(@NonNull Source source) { - getMapView().getNativeMapView().addSource(source); + nativeMapView.addSource(source); } /** @@ -209,7 +305,7 @@ public class MapboxMap { */ @UiThread public void removeSource(@NonNull String sourceId) throws NoSuchSourceException { - getMapView().getNativeMapView().removeSource(sourceId); + nativeMapView.removeSource(sourceId); } /** @@ -220,7 +316,7 @@ public class MapboxMap { */ @UiThread public void removeSource(@NonNull Source source) throws NoSuchSourceException { - getMapView().getNativeMapView().removeSource(source); + nativeMapView.removeSource(source); } /** @@ -231,7 +327,7 @@ public class MapboxMap { */ @UiThread public void addImage(@NonNull String name, @NonNull Bitmap image) { - getMapView().getNativeMapView().addImage(name, image); + nativeMapView.addImage(name, image); } /** @@ -241,7 +337,7 @@ public class MapboxMap { */ @UiThread public void removeImage(String name) { - getMapView().getNativeMapView().removeImage(name); + nativeMapView.removeImage(name); } // @@ -263,7 +359,7 @@ public class MapboxMap { return; } minZoomLevel = minZoom; - mapView.setMinZoom(minZoom); + nativeMapView.setMinZoom(minZoom); } /** @@ -276,7 +372,7 @@ public class MapboxMap { @UiThread public double getMinZoom() { if (minZoomLevel == -1) { - return minZoomLevel = mapView.getMinZoom(); + return minZoomLevel = nativeMapView.getMinZoom(); } return minZoomLevel; } @@ -300,7 +396,7 @@ public class MapboxMap { return; } maxZoomLevel = maxZoom; - mapView.setMaxZoom(maxZoom); + nativeMapView.setMaxZoom(maxZoom); } /** @@ -313,7 +409,7 @@ public class MapboxMap { @UiThread public double getMaxZoom() { if (maxZoomLevel == -1) { - return maxZoomLevel = mapView.getMaxZoom(); + return maxZoomLevel = nativeMapView.getMaxZoom(); } return maxZoomLevel; } @@ -354,9 +450,6 @@ public class MapboxMap { * @return the MyLocationViewSettings associated with this map */ public MyLocationViewSettings getMyLocationViewSettings() { - if (myLocationViewSettings == null) { - myLocationViewSettings = new MyLocationViewSettings(mapView, mapView.getUserLocationView()); - } return myLocationViewSettings; } @@ -420,6 +513,9 @@ public class MapboxMap { @UiThread public final void moveCamera(CameraUpdate update) { moveCamera(update, null); + // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo` + // invalidate camera position to provide OnCameraChange event. + invalidateCameraPosition(); } /** @@ -432,10 +528,10 @@ public class MapboxMap { */ @UiThread public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) { - mapView.post(new Runnable() { + new Handler().post(new Runnable() { @Override public void run() { - transform.moveCamera(update, callback); + transform.moveCamera(MapboxMap.this, update, callback); } }); } @@ -559,10 +655,10 @@ public class MapboxMap { */ @UiThread public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, final boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { - mapView.post(new Runnable() { + new Handler().post(new Runnable() { @Override public void run() { - transform.easeCamera(update, durationMs, easingInterpolator, resetTrackingMode, callback); + transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, resetTrackingMode, callback); } }); } @@ -634,10 +730,10 @@ public class MapboxMap { */ @UiThread public final void animateCamera(final CameraUpdate update, final int durationMs, final MapboxMap.CancelableCallback callback) { - mapView.post(new Runnable() { + new Handler().post(new Runnable() { @Override public void run() { - transform.animateCamera(update, durationMs, callback); + transform.animateCamera(MapboxMap.this, update, durationMs, callback); } }); } @@ -648,7 +744,7 @@ public class MapboxMap { void invalidateCameraPosition() { CameraPosition cameraPosition = transform.invalidateCameraPosition(); if (cameraPosition != null) { - mapView.updateCameraPosition(cameraPosition); + transform.updateCameraPosition(cameraPosition); } } @@ -674,7 +770,7 @@ public class MapboxMap { */ @UiThread public boolean isDebugActive() { - return mapView.isDebugActive(); + return nativeMapView.getDebug(); } /** @@ -687,21 +783,21 @@ public class MapboxMap { */ @UiThread public void setDebugActive(boolean debugActive) { - mapView.setDebugActive(debugActive); + nativeMapView.setDebug(debugActive); } /** * <p> * Cycles through the map debug options. * </p> - * The value of {@link MapView#isDebugActive()} reflects whether there are + * The value of isDebugActive reflects whether there are * any map debug options enabled or disabled. * - * @see MapView#isDebugActive() + * @see #isDebugActive() */ @UiThread public void cycleDebugOptions() { - mapView.cycleDebugOptions(); + nativeMapView.cycleDebugOptions(); } // @@ -739,7 +835,7 @@ public class MapboxMap { */ @UiThread public void setStyleUrl(@NonNull String url) { - mapView.setStyleUrl(url); + nativeMapView.setStyleUrl(url); } /** @@ -775,7 +871,7 @@ public class MapboxMap { @UiThread @NonNull public String getStyleUrl() { - return mapView.getStyleUrl(); + return nativeMapView.getStyleUrl(); } // @@ -797,7 +893,7 @@ public class MapboxMap { @Deprecated @UiThread public void setAccessToken(@NonNull String accessToken) { - mapView.setAccessToken(accessToken); + nativeMapView.setAccessToken(accessToken); } /** @@ -815,17 +911,13 @@ public class MapboxMap { @UiThread @Nullable public String getAccessToken() { - return mapView.getAccessToken(); + return nativeMapView.getAccessToken(); } // // Annotations // - void setTilt(double tilt) { - mapView.setTilt(tilt); - } - /** * <p> * Adds a marker to this map. @@ -1152,7 +1244,7 @@ public class MapboxMap { Timber.w("marker was null, so just returning"); return; } - annotationManager.selectMarker(marker, this); + annotationManager.selectMarker(marker); } /** @@ -1189,7 +1281,7 @@ public class MapboxMap { * @return the associated MarkerViewManager */ public MarkerViewManager getMarkerViewManager() { - return annotationManager.getMarkerViewManager(this); + return annotationManager.getMarkerViewManager(); } // @@ -1208,7 +1300,7 @@ public class MapboxMap { */ @UiThread public void setInfoWindowAdapter(@Nullable InfoWindowAdapter infoWindowAdapter) { - infoWindowManager.setInfoWindowAdapter(infoWindowAdapter); + annotationManager.getInfoWindowManager().setInfoWindowAdapter(infoWindowAdapter); } /** @@ -1219,7 +1311,7 @@ public class MapboxMap { @UiThread @Nullable public InfoWindowAdapter getInfoWindowAdapter() { - return infoWindowManager.getInfoWindowAdapter(); + return annotationManager.getInfoWindowManager().getInfoWindowAdapter(); } /** @@ -1229,7 +1321,7 @@ public class MapboxMap { */ @UiThread public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { - infoWindowManager.setAllowConcurrentMultipleOpenInfoWindows(allow); + annotationManager.getInfoWindowManager().setAllowConcurrentMultipleOpenInfoWindows(allow); } /** @@ -1239,12 +1331,12 @@ public class MapboxMap { */ @UiThread public boolean isAllowConcurrentMultipleOpenInfoWindows() { - return infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows(); + return annotationManager.getInfoWindowManager().isAllowConcurrentMultipleOpenInfoWindows(); } // Internal API List<InfoWindow> getInfoWindows() { - return infoWindowManager.getInfoWindows(); + return annotationManager.getInfoWindowManager().getInfoWindows(); } AnnotationManager getAnnotationManager() { @@ -1279,7 +1371,7 @@ public class MapboxMap { * @param bottom The bottom margin in pixels. */ public void setPadding(int left, int top, int right, int bottom) { - mapView.setContentPadding(left, top, right, bottom); + projection.setContentPadding(new int[]{left, top, right, bottom}, myLocationViewSettings.getPadding()); uiSettings.invalidate(); } @@ -1289,10 +1381,7 @@ public class MapboxMap { * @return An array with length 4 in the LTRB order. */ public int[] getPadding() { - return new int[]{mapView.getContentPaddingLeft(), - mapView.getContentPaddingTop(), - mapView.getContentPaddingRight(), - mapView.getContentPaddingBottom()}; + return projection.getContentPadding(); } // @@ -1334,12 +1423,7 @@ public class MapboxMap { */ @UiThread public void setOnScrollListener(@Nullable OnScrollListener listener) { - onScrollListener = listener; - } - - // used by MapView - OnScrollListener getOnScrollListener() { - return onScrollListener; + onRegisterTouchListener.onRegisterScrollListener(listener); } /** @@ -1350,12 +1434,7 @@ public class MapboxMap { */ @UiThread public void setOnFlingListener(@Nullable OnFlingListener listener) { - onFlingListener = listener; - } - - // used by MapView - OnFlingListener getOnFlingListener() { - return onFlingListener; + onRegisterTouchListener.onRegisterFlingListener(listener); } /** @@ -1366,12 +1445,7 @@ public class MapboxMap { */ @UiThread public void setOnMapClickListener(@Nullable OnMapClickListener listener) { - onMapClickListener = listener; - } - - // used by MapView - OnMapClickListener getOnMapClickListener() { - return onMapClickListener; + onRegisterTouchListener.onRegisterMapClickListener(listener); } /** @@ -1382,12 +1456,7 @@ public class MapboxMap { */ @UiThread public void setOnMapLongClickListener(@Nullable OnMapLongClickListener listener) { - onMapLongClickListener = listener; - } - - // used by MapView - OnMapLongClickListener getOnMapLongClickListener() { - return onMapLongClickListener; + onRegisterTouchListener.onRegisterMapLongClickListener(listener); } /** @@ -1398,7 +1467,7 @@ public class MapboxMap { */ @UiThread public void setOnInfoWindowClickListener(@Nullable OnInfoWindowClickListener listener) { - infoWindowManager.setOnInfoWindowClickListener(listener); + getAnnotationManager().getInfoWindowManager().setOnInfoWindowClickListener(listener); } /** @@ -1408,7 +1477,7 @@ public class MapboxMap { */ @UiThread public OnInfoWindowClickListener getOnInfoWindowClickListener() { - return infoWindowManager.getOnInfoWindowClickListener(); + return getAnnotationManager().getInfoWindowManager().getOnInfoWindowClickListener(); } /** @@ -1420,7 +1489,7 @@ public class MapboxMap { @UiThread public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) { - infoWindowManager.setOnInfoWindowLongClickListener(listener); + getAnnotationManager().getInfoWindowManager().setOnInfoWindowLongClickListener(listener); } /** @@ -1429,11 +1498,11 @@ public class MapboxMap { * @return Current active InfoWindow long Click Listener */ public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { - return infoWindowManager.getOnInfoWindowLongClickListener(); + return getAnnotationManager().getInfoWindowManager().getOnInfoWindowLongClickListener(); } public void setOnInfoWindowCloseListener(@Nullable OnInfoWindowCloseListener listener) { - infoWindowManager.setOnInfoWindowCloseListener(listener); + getAnnotationManager().getInfoWindowManager().setOnInfoWindowCloseListener(listener); } /** @@ -1443,7 +1512,7 @@ public class MapboxMap { */ @UiThread public OnInfoWindowCloseListener getOnInfoWindowCloseListener() { - return infoWindowManager.getOnInfoWindowCloseListener(); + return getAnnotationManager().getInfoWindowManager().getOnInfoWindowCloseListener(); } // @@ -1474,13 +1543,13 @@ public class MapboxMap { */ @UiThread public void setMyLocationEnabled(boolean enabled) { - if (!mapView.isPermissionsAccepted()) { + if (!trackingSettings.isPermissionsAccepted()) { Timber.e("Could not activate user location tracking: " + "user did not accept the permission or permissions were not requested."); return; } myLocationEnabled = enabled; - mapView.setMyLocationEnabled(enabled); + trackingSettings.setMyLocationEnabled(enabled); } /** @@ -1491,7 +1560,7 @@ public class MapboxMap { @UiThread @Nullable public Location getMyLocation() { - return mapView.getMyLocation(); + return trackingSettings.getMyLocation(); } /** @@ -1504,7 +1573,7 @@ public class MapboxMap { @UiThread public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { - mapView.setOnMyLocationChangeListener(listener); + trackingSettings.setOnMyLocationChangeListener(listener); } /** @@ -1514,15 +1583,8 @@ public class MapboxMap { * To unset the callback, use null. */ @UiThread - public void setOnMyLocationTrackingModeChangeListener - (@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { - onMyLocationTrackingModeChangeListener = listener; - } - - // used by MapView - MapboxMap.OnMyLocationTrackingModeChangeListener getOnMyLocationTrackingModeChangeListener - () { - return onMyLocationTrackingModeChangeListener; + public void setOnMyLocationTrackingModeChangeListener(@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) { + trackingSettings.setOnMyLocationTrackingModeChangeListener(listener); } /** @@ -1532,26 +1594,8 @@ public class MapboxMap { * To unset the callback, use null. */ @UiThread - public void setOnMyBearingTrackingModeChangeListener - (@Nullable OnMyBearingTrackingModeChangeListener listener) { - onMyBearingTrackingModeChangeListener = listener; - } - - // used by MapView - OnMyBearingTrackingModeChangeListener getOnMyBearingTrackingModeChangeListener() { - return onMyBearingTrackingModeChangeListener; - } - - MapView getMapView() { - return mapView; - } - - void setUiSettings(UiSettings uiSettings) { - this.uiSettings = uiSettings; - } - - void setProjection(Projection projection) { - this.projection = projection; + public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) { + trackingSettings.setOnMyBearingTrackingModeChangeListener(listener); } // @@ -1559,13 +1603,6 @@ public class MapboxMap { // /** - * Triggers an invalidation of the map view. - */ - public void invalidate() { - mapView.invalidate(); - } - - /** * Takes a snapshot of the map. * * @param callback Callback method invoked when the snapshot is taken. @@ -1573,7 +1610,8 @@ public class MapboxMap { */ @UiThread public void snapshot(@NonNull SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) { - mapView.snapshot(callback, bitmap); + // FIXME 12/02/2016 + //mapView.snapshot(callback, bitmap); } /** @@ -1583,7 +1621,8 @@ public class MapboxMap { */ @UiThread public void snapshot(@NonNull SnapshotReadyCallback callback) { - mapView.snapshot(callback, null); + // FIXME 12/02/2016 + //mapView.snapshot(callback, null); } /** @@ -1597,7 +1636,7 @@ public class MapboxMap { @NonNull public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... layerIds) { - return mapView.getNativeMapView().queryRenderedFeatures(coordinates, layerIds); + return nativeMapView.queryRenderedFeatures(coordinates, layerIds); } /** @@ -1611,21 +1650,7 @@ public class MapboxMap { @NonNull public List<Feature> 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(); - } - } + return nativeMapView.queryRenderedFeatures(coordinates, layerIds); } // @@ -1685,6 +1710,20 @@ public class MapboxMap { } /** + * Interface definition for a callback to be invoked when a user registers an listener that is + * related to touch and click events. + */ + interface OnRegisterTouchListener { + void onRegisterMapClickListener(OnMapClickListener listener); + + void onRegisterMapLongClickListener(OnMapLongClickListener listener); + + void onRegisterScrollListener(OnScrollListener listener); + + void onRegisterFlingListener(OnFlingListener listener); + } + + /** * Interface definition for a callback to be invoked when the user clicks on the map view. * * @see MapboxMap#setOnMapClickListener(OnMapClickListener) @@ -1939,7 +1978,7 @@ public class MapboxMap { /** * Interface definition for a callback to be invoked when the the My Location tracking mode changes. * - * @see MapView#setMyLocationTrackingMode(int) + * @see TrackingSettings#setMyLocationTrackingMode(int) */ public interface OnMyLocationTrackingModeChangeListener { @@ -1954,7 +1993,7 @@ public class MapboxMap { /** * Interface definition for a callback to be invoked when the the My Location tracking mode changes. * - * @see MapView#setMyLocationTrackingMode(int) + * @see TrackingSettings#setMyLocationTrackingMode(int) */ public interface OnMyBearingTrackingModeChangeListener { 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 c3d12c4a7a..6189087686 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,14 +9,12 @@ import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.DisplayMetrics; -import timber.log.Timber; import android.view.Surface; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.Polyline; -import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; import com.mapbox.mapboxsdk.offline.OfflineManager; @@ -32,10 +30,13 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import timber.log.Timber; + // Class that wraps the native methods for convenience final class NativeMapView { - boolean destroyed = false; + // Flag to indicating destroy was called + private boolean destroyed = false; // Holds the pointer to JNI NativeMapView private long nativeMapViewPtr = 0; @@ -43,8 +44,10 @@ final class NativeMapView { // Used for callbacks private MapView mapView; + // Device density private final float pixelRatio; + // Listeners for Map change events private CopyOnWriteArrayList<MapView.OnMapChangedListener> onMapChangedListeners; // @@ -139,6 +142,9 @@ final class NativeMapView { } public void resizeView(int width, int height) { + width = (int) (width / pixelRatio); + height = (int) (height / pixelRatio); + if (width < 0) { throw new IllegalArgumentException("width cannot be negative."); } @@ -208,6 +214,10 @@ final class NativeMapView { nativeSetStyleUrl(nativeMapViewPtr, url); } + public String getStyleUrl() { + return nativeGetStyleUrl(nativeMapViewPtr); + } + public void setStyleJson(String newStyleJson) { nativeSetStyleJson(nativeMapViewPtr, newStyleJson); } @@ -237,7 +247,7 @@ final class NativeMapView { } public void moveBy(double dx, double dy, long duration) { - nativeMoveBy(nativeMapViewPtr, dx, dy, duration); + nativeMoveBy(nativeMapViewPtr, dx / pixelRatio, dy / pixelRatio, duration); } public void setLatLng(LatLng latLng) { @@ -273,7 +283,7 @@ final class NativeMapView { } public void scaleBy(double ds, double cx, double cy, long duration) { - nativeScaleBy(nativeMapViewPtr, ds, cx, cy, duration); + nativeScaleBy(nativeMapViewPtr, ds, cx / pixelRatio, cy / pixelRatio, duration); } public void setScale(double scale) { @@ -285,7 +295,7 @@ final class NativeMapView { } public void setScale(double scale, double cx, double cy, long duration) { - nativeSetScale(nativeMapViewPtr, scale, cx, cy, duration); + nativeSetScale(nativeMapViewPtr, scale, cx / pixelRatio, cy / pixelRatio, duration); } public double getScale() { @@ -330,11 +340,15 @@ final class NativeMapView { public void rotateBy(double sx, double sy, double ex, double ey, long duration) { - nativeRotateBy(nativeMapViewPtr, sx, sy, ex, ey, duration); + nativeRotateBy(nativeMapViewPtr, sx/pixelRatio, sy/pixelRatio, ex, ey, duration); } - public void setContentPadding(double top, double left, double bottom, double right) { - nativeSetContentPadding(nativeMapViewPtr, top, left, bottom, right); + public void setContentPadding(int[] padding) { + nativeSetContentPadding(nativeMapViewPtr, + padding[1] / pixelRatio, + padding[0] / pixelRatio, + padding[3] / pixelRatio, + padding[2] / pixelRatio); } public void setBearing(double degrees) { @@ -346,7 +360,7 @@ final class NativeMapView { } public void setBearing(double degrees, double cx, double cy) { - nativeSetBearingXY(nativeMapViewPtr, degrees, cx, cy); + nativeSetBearingXY(nativeMapViewPtr, degrees, cx/pixelRatio, cy/pixelRatio); } public double getBearing() { @@ -443,8 +457,8 @@ final class NativeMapView { nativeSetReachability(nativeMapViewPtr, status); } - public double getMetersPerPixelAtLatitude(double lat, double zoom) { - return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, zoom); + public double getMetersPerPixelAtLatitude(double lat) { + return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, getZoom()); } public ProjectedMeters projectedMetersForLatLng(LatLng latLng) { @@ -456,11 +470,13 @@ final class NativeMapView { } public PointF pixelForLatLng(LatLng latLng) { - return nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + PointF pointF = nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio); + return pointF; } public LatLng latLngForPixel(PointF pixel) { - return nativeLatLngForPixel(nativeMapViewPtr, pixel.x, pixel.y); + return nativeLatLngForPixel(nativeMapViewPtr, pixel.x / pixelRatio, pixel.y / pixelRatio); } public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) { @@ -636,6 +652,8 @@ final class NativeMapView { private native void nativeSetStyleUrl(long nativeMapViewPtr, String url); + private native String nativeGetStyleUrl(long nativeMapViewPtr); + private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson); private native String nativeGetStyleJson(long nativeMapViewPtr); @@ -782,6 +800,14 @@ final class NativeMapView { private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl); + int getWidth() { + return mapView.getWidth(); + } + + int getHeight() { + return mapView.getHeight(); + } + // // MapChangeEvents // 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 e06ed38433..5a28d0c7a0 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 @@ -7,6 +7,7 @@ import android.support.annotation.NonNull; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.VisibleRegion; +import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; /** * A projection is used to translate between on screen location and geographic coordinates on @@ -15,15 +16,33 @@ import com.mapbox.mapboxsdk.geometry.VisibleRegion; */ public class Projection { - private final MapView mapView; - private final float screenDensity; - private final PointF screenLocationPoint; + private final NativeMapView nativeMapView; + private int[] contentPadding; - Projection(@NonNull MapView mapView) { - this.mapView = mapView; - this.screenLocationPoint = new PointF(); - this.screenDensity = mapView.getContext() != null ? /* return default if unit test */ - mapView.getContext().getResources().getDisplayMetrics().density : 1.0f; + Projection(@NonNull NativeMapView nativeMapView) { + this.nativeMapView = nativeMapView; + this.contentPadding = new int[]{0, 0, 0, 0}; + } + + void setContentPadding(int[] contentPadding, int[] userLocationViewPadding) { + this.contentPadding = contentPadding; + + int[] padding = new int[]{ + contentPadding[0] + userLocationViewPadding[0], + contentPadding[1] + userLocationViewPadding[1], + contentPadding[2] + userLocationViewPadding[2], + contentPadding[3] + userLocationViewPadding[3] + }; + + nativeMapView.setContentPadding(padding); + } + + int[] getContentPadding() { + return contentPadding; + } + + public void invalidateContentPadding(int[] userLocationViewPadding) { + setContentPadding(contentPadding, userLocationViewPadding); } /** @@ -37,7 +56,7 @@ public class Projection { * @return The distance measured in meters. */ public double getMetersPerPixelAtLatitude(@FloatRange(from = -90, to = 90) double latitude) { - return mapView.getMetersPerPixelAtLatitude(latitude); + return nativeMapView.getMetersPerPixelAtLatitude(latitude); } /** @@ -50,8 +69,7 @@ public class Projection { * the given screen point does not intersect the ground plane. */ public LatLng fromScreenLocation(PointF point) { - screenLocationPoint.set(point.x / screenDensity, point.y / screenDensity); - return mapView.fromNativeScreenLocation(screenLocationPoint); + return nativeMapView.latLngForPixel(point); } /** @@ -63,10 +81,10 @@ public class Projection { public VisibleRegion getVisibleRegion() { LatLngBounds.Builder builder = new LatLngBounds.Builder(); - float left = mapView.getContentPaddingLeft(); - float right = mapView.getWidth() - mapView.getContentPaddingRight(); - float top = mapView.getContentPaddingTop(); - float bottom = mapView.getHeight() - mapView.getContentPaddingBottom(); + float left = contentPadding[0]; + float right = nativeMapView.getWidth() - contentPadding[2]; + float top = contentPadding[1]; + float bottom = nativeMapView.getHeight() - contentPadding[3]; LatLng topLeft = fromScreenLocation(new PointF(left, top)); LatLng topRight = fromScreenLocation(new PointF(right, top)); @@ -90,18 +108,14 @@ public class Projection { * @return A Point representing the screen location in screen pixels. */ public PointF toScreenLocation(LatLng location) { - PointF pointF = mapView.toNativeScreenLocation(location); - pointF.set(pointF.x * screenDensity, pointF.y * screenDensity); - return pointF; + return nativeMapView.pixelForLatLng(location); } - /** - * Calculates a zoom level based on minimum scale and current scale from MapView - * - * @param minScale The minimum scale to calculate the zoom level. - * @return zoom level that fits the MapView. - */ - public double calculateZoom(float minScale) { - return Math.log(mapView.getScale() * minScale) / Math.log(2); + float getHeight() { + return nativeMapView.getHeight(); + } + + float getWidth() { + return nativeMapView.getWidth(); } } 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 ac620ca7ba..560f7375c9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java @@ -1,22 +1,30 @@ package com.mapbox.mapboxsdk.maps; +import android.Manifest; +import android.content.pm.PackageManager; +import android.graphics.PointF; +import android.location.Location; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; +import android.support.v4.content.ContextCompat; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; +import com.mapbox.mapboxsdk.location.LocationListener; +import com.mapbox.mapboxsdk.location.LocationServices; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; /** * Settings for the user location and bearing tracking of a MapboxMap. */ -public class TrackingSettings { +public final class TrackingSettings { - private MapView mapView; - private UiSettings uiSettings; - private boolean dismissLocationTrackingOnGesture = true; - private boolean dismissBearingTrackingOnGesture = true; + private final MyLocationView myLocationView; + private final UiSettings uiSettings; + private final FocalPointChangeListener focalPointChangedListener; + private LocationListener myLocationListener; @MyLocationTracking.Mode private int myLocationTrackingMode; @@ -24,8 +32,14 @@ public class TrackingSettings { @MyBearingTracking.Mode private int myBearingTrackingMode; - TrackingSettings(@NonNull MapView mapView, UiSettings uiSettings) { - this.mapView = mapView; + private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener; + private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener; + private boolean dismissLocationTrackingOnGesture = true; + private boolean dismissBearingTrackingOnGesture = true; + + TrackingSettings(@NonNull MyLocationView myLocationView, UiSettings uiSettings, FocalPointChangeListener focalPointChangedListener) { + this.myLocationView = myLocationView; + this.focalPointChangedListener = focalPointChangedListener; this.uiSettings = uiSettings; } @@ -45,7 +59,17 @@ public class TrackingSettings { @UiThread public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { this.myLocationTrackingMode = myLocationTrackingMode; - mapView.setMyLocationTrackingMode(myLocationTrackingMode); + myLocationView.setMyLocationTrackingMode(myLocationTrackingMode); + + if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + focalPointChangedListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY())); + } else { + focalPointChangedListener.onFocalPointChanged(null); + } + + if (onMyLocationTrackingModeChangeListener != null) { + onMyLocationTrackingModeChangeListener.onMyLocationTrackingModeChange(myLocationTrackingMode); + } } /** @@ -79,7 +103,10 @@ public class TrackingSettings { @UiThread public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { this.myBearingTrackingMode = myBearingTrackingMode; - mapView.setMyBearingTrackingMode(myBearingTrackingMode); + myLocationView.setMyBearingTrackingMode(myBearingTrackingMode); + if (onMyBearingTrackingModeChangeListener != null) { + onMyBearingTrackingModeChangeListener.onMyBearingTrackingModeChange(myBearingTrackingMode); + } } /** @@ -220,7 +247,7 @@ public class TrackingSettings { * @param translate * @param rotate */ - public void resetTrackingModesIfRequired(boolean translate, boolean rotate) { + 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); @@ -232,7 +259,57 @@ public class TrackingSettings { } } - public void resetTrackingModesIfRequired(CameraPosition cameraPosition) { + void resetTrackingModesIfRequired(CameraPosition cameraPosition) { resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1); } + + public void invalidateFocalPointForTracking(MyLocationView myLocationView) { + if (!isLocationTrackingDisabled()) { + focalPointChangedListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(), myLocationView.getCenterY())); + } else { + focalPointChangedListener.onFocalPointChanged(null); + } + } + + void setMyLocationEnabled(boolean enabled) { + myLocationView.setEnabled(enabled); + } + + Location getMyLocation() { + return myLocationView.getLocation(); + } + + void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) { + if (listener != null) { + myLocationListener = new LocationListener() { + @Override + public void onLocationChanged(Location location) { + if (listener != null) { + listener.onMyLocationChange(location); + } + } + }; + LocationServices.getLocationServices(myLocationView.getContext()).addLocationListener(myLocationListener); + } else { + LocationServices.getLocationServices(myLocationView.getContext()).removeLocationListener(myLocationListener); + myLocationListener = null; + } + } + + boolean isPermissionsAccepted() { + return (ContextCompat.checkSelfPermission(myLocationView.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) || + ContextCompat.checkSelfPermission(myLocationView.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; + } + + void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener) { + this.onMyLocationTrackingModeChangeListener = onMyLocationTrackingModeChangeListener; + } + + void setOnMyBearingTrackingModeChangeListener(MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener) { + this.onMyBearingTrackingModeChangeListener = onMyBearingTrackingModeChangeListener; + } + + MyLocationView getMyLocationView(){ + return 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 1532bb6745..4aefb0bb7e 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 @@ -1,10 +1,15 @@ package com.mapbox.mapboxsdk.maps; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import java.util.concurrent.TimeUnit; @@ -16,18 +21,23 @@ import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED; * Responsible for synchronising {@link CameraPosition} state and notifying {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraChangeListener}. * </p> */ -class Transform { +final class Transform implements MapView.OnMapChangedListener { - private NativeMapView mapView; - private MapboxMap mapboxMap; + private final NativeMapView mapView; + private final MarkerViewManager markerViewManager; + private final TrackingSettings trackingSettings; + private final MyLocationView myLocationView; private CameraPosition cameraPosition; private MapboxMap.CancelableCallback cameraCancelableCallback; private MapboxMap.OnCameraChangeListener onCameraChangeListener; - Transform(NativeMapView mapView, MapboxMap mapboxMap) { + Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings) { this.mapView = mapView; - this.mapboxMap = mapboxMap; + this.markerViewManager = markerViewManager; + this.trackingSettings = trackingSettings; + this.myLocationView = trackingSettings.getMyLocationView(); + mapView.addOnMapChangedListener(this); } // @@ -43,25 +53,36 @@ class Transform { } @UiThread - final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) { + void updateCameraPosition(@NonNull CameraPosition position) { + if (myLocationView != null) { + myLocationView.setCameraPosition(position); + } + markerViewManager.setTilt((float) position.tilt); + } + + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (change == MapView.REGION_DID_CHANGE_ANIMATED) { + invalidateCameraPosition(); + } + } + + @UiThread + final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, MapboxMap.CancelableCallback callback) { cameraPosition = update.getCameraPosition(mapboxMap); - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + trackingSettings.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) { + final void easeCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator, boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) { cameraPosition = update.getCameraPosition(mapboxMap); if (resetTrackingMode) { - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + trackingSettings.resetTrackingModesIfRequired(cameraPosition); } cancelTransitions(); @@ -83,9 +104,9 @@ class Transform { } @UiThread - final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { + final void animateCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) { cameraPosition = update.getCameraPosition(mapboxMap); - mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition); + trackingSettings.resetTrackingModesIfRequired(cameraPosition); cancelTransitions(); if (callback != null) { @@ -140,4 +161,110 @@ class Transform { private long getDurationNano(long durationMs) { return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0; } + + // + // non Camera API + // + + // Zoom in or out + + double getZoom() { + return cameraPosition.zoom; + } + + void zoom(boolean zoomIn) { + zoom(zoomIn, -1.0f, -1.0f); + } + + void zoom(boolean zoomIn, float x, float y) { + // Cancel any animation + cancelTransitions(); + + if (zoomIn) { + mapView.scaleBy(2.0, x, y, MapboxConstants.ANIMATION_DURATION); + } else { + mapView.scaleBy(0.5, x, y, MapboxConstants.ANIMATION_DURATION); + } + } + + // Direction + double getBearing() { + double direction = -mapView.getBearing(); + + while (direction > 360) { + direction -= 360; + } + while (direction < 0) { + direction += 360; + } + + return direction; + } + + double getRawBearing(){ + return mapView.getBearing(); + } + + void setBearing(double bearing) { + if (myLocationView != null) { + myLocationView.setBearing(bearing); + } + mapView.setBearing(bearing); + } + + void setBearing(double bearing, float focalX, float focalY) { + if (myLocationView != null) { + myLocationView.setBearing(bearing); + } + mapView.setBearing(bearing, focalX, focalY); + } + + + // + // LatLng / CenterCoordinate + // + + LatLng getLatLng() { + return mapView.getLatLng(); + } + + // + // Pitch / Tilt + // + + double getTilt() { + return mapView.getPitch(); + } + + void setTilt(Double pitch) { + if (myLocationView != null) { + myLocationView.setTilt(pitch); + } + markerViewManager.setTilt(pitch.floatValue()); + mapView.setPitch(pitch, 0); + } + + // + // Center coordinate + // + + LatLng getCenterCoordinate() { + return mapView.getLatLng(); + } + + void setCenterCoordinate(LatLng centerCoordinate) { + mapView.setLatLng(centerCoordinate); + } + + void setGestureInProgress(boolean gestureInProgress) { + mapView.setGestureInProgress(gestureInProgress); + } + + void zoomBy(double pow, float x, float y) { + mapView.scaleBy(pow, x, y); + } + + void moveBy(double offsetX, double offsetY, long duration) { + mapView.moveBy(offsetX, offsetY, duration); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index d6ad80d11e..1523fcefa7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -1,23 +1,32 @@ package com.mapbox.mapboxsdk.maps; +import android.graphics.Color; import android.graphics.PointF; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; +import android.support.v4.content.ContextCompat; import android.view.Gravity; import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.mapbox.mapboxsdk.R; +import com.mapbox.mapboxsdk.maps.widgets.CompassView; +import com.mapbox.mapboxsdk.utils.ColorUtils; /** * Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings(). */ -public class UiSettings { - - private MapView mapView; +public final class UiSettings { - private CompassViewSettings compassSettings; - private ViewSettings logoSettings; - private ViewSettings attributionSettings; + private final FocalPointChangeListener focalPointChangeListener; + private final Projection projection; + private final CompassView compassView; + private final ImageView attributionsView; + private final View logoView; + private float pixelRatio; private boolean rotateGesturesEnabled = true; private boolean rotateGestureChangeAllowed = true; @@ -35,13 +44,17 @@ public class UiSettings { private boolean deselectMarkersOnTap = true; - private PointF focalPoint; + private PointF userProvidedFocalPoint; - UiSettings(@NonNull MapView mapView) { - this.mapView = mapView; - this.compassSettings = new CompassViewSettings(); - this.logoSettings = new ViewSettings(); - this.attributionSettings = new ViewSettings(); + UiSettings(@NonNull Projection projection, @NonNull FocalPointChangeListener listener, @NonNull CompassView compassView, @NonNull ImageView attributionsView, @NonNull View logoView) { + this.projection = projection; + this.focalPointChangeListener = listener; + this.compassView = compassView; + this.attributionsView = attributionsView; + this.logoView = logoView; + if(logoView.getResources()!=null) { + this.pixelRatio = logoView.getResources().getDisplayMetrics().density; + } } /** @@ -56,8 +69,7 @@ public class UiSettings { * @param compassEnabled True to enable the compass; false to disable the compass. */ public void setCompassEnabled(boolean compassEnabled) { - compassSettings.setEnabled(compassEnabled); - mapView.setCompassEnabled(compassEnabled); + compassView.setEnabled(compassEnabled); } /** @@ -66,7 +78,7 @@ public class UiSettings { * @return True if the compass is enabled; false if the compass is disabled. */ public boolean isCompassEnabled() { - return compassSettings.isEnabled(); + return compassView.isEnabled(); } /** @@ -81,8 +93,7 @@ public class UiSettings { */ @UiThread public void setCompassGravity(int gravity) { - compassSettings.setGravity(gravity); - mapView.setCompassGravity(gravity); + setWidgetGravity(compassView, gravity); } /** @@ -94,8 +105,7 @@ public class UiSettings { * @param compassFadeFacingNorth True to enable the fading animation; false to disable it */ public void setCompassFadeFacingNorth(boolean compassFadeFacingNorth) { - compassSettings.setFadeFacingNorth(compassFadeFacingNorth); - mapView.setCompassFadeFacingNorth(compassFadeFacingNorth); + compassView.fadeCompassViewFacingNorth(compassFadeFacingNorth); } /** @@ -103,8 +113,8 @@ public class UiSettings { * * @return True if the compass will fade, false if it remains visible */ - public boolean isCompassFadeWhenFacingNorth(){ - return compassSettings.isFadeFacingNorth(); + public boolean isCompassFadeWhenFacingNorth() { + return compassView.isFadeCompassViewFacingNorth(); } /** @@ -113,7 +123,7 @@ public class UiSettings { * @return The gravity */ public int getCompassGravity() { - return compassSettings.getGravity(); + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).gravity; } /** @@ -127,8 +137,7 @@ public class UiSettings { */ @UiThread public void setCompassMargins(int left, int top, int right, int bottom) { - compassSettings.setMargins(new int[]{left, top, right, bottom}); - mapView.setCompassMargins(left, top, right, bottom); + setWidgetMargins(compassView, left, top, right, bottom); } /** @@ -137,7 +146,7 @@ public class UiSettings { * @return The left margin in pixels */ public int getCompassMarginLeft() { - return compassSettings.getMargins()[0]; + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).leftMargin; } /** @@ -146,7 +155,7 @@ public class UiSettings { * @return The top margin in pixels */ public int getCompassMarginTop() { - return compassSettings.getMargins()[1]; + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).topMargin; } /** @@ -155,7 +164,7 @@ public class UiSettings { * @return The right margin in pixels */ public int getCompassMarginRight() { - return compassSettings.getMargins()[2]; + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).rightMargin; } /** @@ -164,7 +173,7 @@ public class UiSettings { * @return The bottom margin in pixels */ public int getCompassMarginBottom() { - return compassSettings.getMargins()[3]; + return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).bottomMargin; } /** @@ -176,8 +185,7 @@ public class UiSettings { * @param enabled True to enable the logo; false to disable the logo. */ public void setLogoEnabled(boolean enabled) { - logoSettings.setEnabled(enabled); - mapView.setLogoEnabled(enabled); + logoView.setVisibility(enabled ? View.VISIBLE : View.GONE); } /** @@ -186,7 +194,7 @@ public class UiSettings { * @return True if the logo is enabled; false if the logo is disabled. */ public boolean isLogoEnabled() { - return logoSettings.isEnabled(); + return logoView.getVisibility() == View.VISIBLE; } /** @@ -200,8 +208,7 @@ public class UiSettings { * @see Gravity */ public void setLogoGravity(int gravity) { - logoSettings.setGravity(gravity); - mapView.setLogoGravity(gravity); + setWidgetGravity(logoView, gravity); } /** @@ -210,7 +217,7 @@ public class UiSettings { * @return The gravity */ public int getLogoGravity() { - return logoSettings.getGravity(); + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).gravity; } /** @@ -223,8 +230,7 @@ public class UiSettings { * @param bottom The bottom margin in pixels. */ public void setLogoMargins(int left, int top, int right, int bottom) { - logoSettings.setMargins(new int[]{left, top, right, bottom}); - mapView.setLogoMargins(left, top, right, bottom); + setWidgetMargins(logoView, left, top, right, bottom); } /** @@ -233,7 +239,7 @@ public class UiSettings { * @return The left margin in pixels */ public int getLogoMarginLeft() { - return logoSettings.getMargins()[0]; + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).leftMargin; } /** @@ -242,7 +248,7 @@ public class UiSettings { * @return The top margin in pixels */ public int getLogoMarginTop() { - return logoSettings.getMargins()[1]; + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).topMargin; } /** @@ -251,7 +257,7 @@ public class UiSettings { * @return The right margin in pixels */ public int getLogoMarginRight() { - return logoSettings.getMargins()[2]; + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).rightMargin; } /** @@ -260,7 +266,7 @@ public class UiSettings { * @return The bottom margin in pixels */ public int getLogoMarginBottom() { - return logoSettings.getMargins()[3]; + return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).bottomMargin; } /** @@ -272,8 +278,7 @@ public class UiSettings { * @param enabled True to enable the attribution; false to disable the attribution. */ public void setAttributionEnabled(boolean enabled) { - attributionSettings.setEnabled(enabled); - mapView.setAttributionEnabled(enabled ? View.VISIBLE : View.GONE); + attributionsView.setVisibility(enabled ? View.VISIBLE : View.GONE); } /** @@ -282,7 +287,7 @@ public class UiSettings { * @return True if the attribution is enabled; false if the attribution is disabled. */ public boolean isAttributionEnabled() { - return attributionSettings.isEnabled(); + return attributionsView.getVisibility() == View.VISIBLE; } /** @@ -295,8 +300,7 @@ public class UiSettings { * @see Gravity */ public void setAttributionGravity(int gravity) { - attributionSettings.setGravity(gravity); - mapView.setAttributionGravity(gravity); + setWidgetGravity(attributionsView, gravity); } /** @@ -305,7 +309,7 @@ public class UiSettings { * @return The gravity */ public int getAttributionGravity() { - return attributionSettings.getGravity(); + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).gravity; } /** @@ -317,8 +321,7 @@ public class UiSettings { * @param bottom The bottom margin in pixels. */ public void setAttributionMargins(int left, int top, int right, int bottom) { - attributionSettings.setMargins(new int[]{left, top, right, bottom}); - mapView.setAttributionMargins(left, top, right, bottom); + setWidgetMargins(attributionsView, left, top, right, bottom); } /** @@ -330,17 +333,12 @@ public class UiSettings { * @param tintColor Color to tint the attribution. */ public void setAttributionTintColor(@ColorInt int tintColor) { - attributionSettings.setTintColor(tintColor); - mapView.setAtttibutionTintColor(tintColor); - } - - /** - * Returns the tint color value of the attribution view. - * - * @return The tint color - */ - public int getAttributionTintColor() { - return attributionSettings.getTintColor(); + // Check that the tint color being passed in isn't transparent. + if (Color.alpha(tintColor) == 0) { + ColorUtils.setTintList(attributionsView, ContextCompat.getColor(attributionsView.getContext(), R.color.mapbox_blue)); + } else { + ColorUtils.setTintList(attributionsView, tintColor); + } } /** @@ -349,7 +347,7 @@ public class UiSettings { * @return The left margin in pixels */ public int getAttributionMarginLeft() { - return attributionSettings.getMargins()[0]; + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).leftMargin; } /** @@ -358,7 +356,7 @@ public class UiSettings { * @return The top margin in pixels */ public int getAttributionMarginTop() { - return attributionSettings.getMargins()[1]; + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).topMargin; } /** @@ -367,7 +365,7 @@ public class UiSettings { * @return The right margin in pixels */ public int getAttributionMarginRight() { - return attributionSettings.getMargins()[2]; + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).rightMargin; } /** @@ -376,7 +374,7 @@ public class UiSettings { * @return The bottom margin in pixels */ public int getAttributionMarginBottom() { - return attributionSettings.getMargins()[3]; + return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).bottomMargin; } /** @@ -593,8 +591,8 @@ public class UiSettings { * @param focalPoint the focal point to be used. */ public void setFocalPoint(@Nullable PointF focalPoint) { - this.focalPoint = focalPoint; - mapView.setFocalPoint(focalPoint); + this.userProvidedFocalPoint = focalPoint; + focalPointChangeListener.onFocalPointChanged(focalPoint); } /** @@ -603,7 +601,7 @@ public class UiSettings { * @return The focal point */ public PointF getFocalPoint() { - return focalPoint; + return userProvidedFocalPoint; } /** @@ -612,7 +610,7 @@ public class UiSettings { * @return height in pixels */ public float getHeight() { - return mapView.getMeasuredHeight(); + return projection.getHeight(); } /** @@ -621,15 +619,36 @@ public class UiSettings { * @return widht in pixels */ public float getWidth() { - return mapView.getMeasuredWidth(); + return projection.getWidth(); + } + + float getPixelRatio() { + return pixelRatio; } /** * Invalidates the ViewSettings instances shown on top of the MapView */ public void invalidate() { - mapView.setLogoMargins(getLogoMarginLeft(), getLogoMarginTop(), getLogoMarginRight(), getLogoMarginBottom()); - mapView.setCompassMargins(getCompassMarginLeft(), getCompassMarginTop(), getCompassMarginRight(), getCompassMarginBottom()); - mapView.setAttributionMargins(getAttributionMarginLeft(), getAttributionMarginTop(), getAttributionMarginRight(), getAttributionMarginBottom()); + setLogoMargins(getLogoMarginLeft(), getLogoMarginTop(), getLogoMarginRight(), getLogoMarginBottom()); + setCompassMargins(getCompassMarginLeft(), getCompassMarginTop(), getCompassMarginRight(), getCompassMarginBottom()); + setAttributionMargins(getAttributionMarginLeft(), getAttributionMarginTop(), getAttributionMarginRight(), getAttributionMarginBottom()); + } + + private void setWidgetGravity(@NonNull final View view, int gravity) { + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); + layoutParams.gravity = gravity; + view.setLayoutParams(layoutParams); + } + + private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) { + int contentPadding[] = projection.getContentPadding(); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams(); + left += contentPadding[0]; + top += contentPadding[1]; + right += contentPadding[2]; + bottom += contentPadding[3]; + layoutParams.setMargins(left, top, right, bottom); + view.setLayoutParams(layoutParams); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java deleted file mode 100644 index 4478978853..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ViewSettings.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -/** - * Settings for the overlain views of a MapboxMap. Used by UiSettings. - */ -class ViewSettings { - - private boolean enabled; - private int gravity; - private int[] margins; - private int tintColor; - - public ViewSettings() { - margins = new int[4]; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public int getGravity() { - return gravity; - } - - public void setGravity(int gravity) { - this.gravity = gravity; - } - - public int[] getMargins() { - return margins; - } - - public void setMargins(int[] margins) { - this.margins = margins; - } - - public int getTintColor() { - return tintColor; - } - - public void setTintColor(int tintColor) { - this.tintColor = tintColor; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java index 5e54354dfa..4d9a60ed66 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 @@ -61,6 +61,7 @@ public final class CompassView extends ImageView implements Runnable { setLayoutParams(lp); } + // TODO refactor MapboxMap and replace with interface public void setMapboxMap(@NonNull MapboxMap mapboxMap) { setOnClickListener(new CompassClickListener(mapboxMap, this)); } @@ -121,6 +122,10 @@ public final class CompassView extends ImageView implements Runnable { fadeCompassViewFacingNorth = compassFadeFacingNorth; } + public boolean isFadeCompassViewFacingNorth(){ + return fadeCompassViewFacingNorth; + } + @Override public void run() { if (isFacingNorth() && fadeCompassViewFacingNorth) { 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 386584141e..1f30734d53 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 @@ -379,6 +379,7 @@ public class MyLocationView extends View { } } + // TODO refactor MapboxMap out public void setMapboxMap(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; this.projection = mapboxMap.getProjection(); 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 80bd1b3bef..d8450ff451 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 @@ -4,14 +4,16 @@ import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.IntRange; -import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.mapboxsdk.maps.TrackingSettings; /** * Settings to configure the visual appearance of the MyLocationView. */ public class MyLocationViewSettings { - private MapView mapView; + private Projection projection; + private TrackingSettings trackingSettings; private MyLocationView myLocationView; // @@ -58,13 +60,14 @@ public class MyLocationViewSettings { /** * Creates an instance of MyLocationViewSettings * - * @param mapView the MapView that hosts the MyLocationView + * @param projection the MapView projection * @param myLocationView the MyLocationView to apply the settings to * @see MyLocationView */ - public MyLocationViewSettings(MapView mapView, MyLocationView myLocationView) { - this.mapView = mapView; + public MyLocationViewSettings(Projection projection, MyLocationView myLocationView, TrackingSettings trackingSettings) { + this.projection = projection; this.myLocationView = myLocationView; + this.trackingSettings = trackingSettings; } /** @@ -208,7 +211,8 @@ public class MyLocationViewSettings { public void setPadding(int left, int top, int right, int bottom) { padding = new int[]{left, top, right, bottom}; myLocationView.setContentPadding(padding); - mapView.invalidateContentPadding(); + projection.invalidateContentPadding(padding); + trackingSettings.invalidateFocalPointForTracking(myLocationView); } /** @@ -257,4 +261,8 @@ public class MyLocationViewSettings { this.accuracyTintColor = accuracyTintColor; myLocationView.setAccuracyTint(accuracyTintColor); } + + public void setTilt(double tilt) { + myLocationView.setTilt(tilt); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java index 22e37ec539..a3545df565 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java @@ -1,6 +1,16 @@ package com.mapbox.mapboxsdk.telemetry; +import android.graphics.PointF; +import android.support.annotation.NonNull; + +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + import java.io.Serializable; +import java.util.Hashtable; + +import timber.log.Timber; /** * Constants for Telemetry Metadata @@ -53,7 +63,7 @@ public class MapboxEvent implements Serializable { public static final String ATTRIBUTE_VENDOR_ID = "vendorId"; public static final String ATTRIBUTE_APP_BUNDLE_ID = "appBundleId"; public static final String ATTRIBUTE_MODEL = "model"; - public static final String ATTRIBUTE_OPERATING_SYSTEM= "operatingSystem"; + public static final String ATTRIBUTE_OPERATING_SYSTEM = "operatingSystem"; public static final String ATTRIBUTE_ORIENTATION = "orientation"; public static final String ATTRIBUTE_BATTERY_LEVEL = "batteryLevel"; public static final String ATTRIBUTE_PLUGGED_IN = "pluggedIn"; @@ -63,4 +73,71 @@ public class MapboxEvent implements Serializable { public static final String ATTRIBUTE_CARRIER = "carrier"; public static final String ATTRIBUTE_CELLULAR_NETWORK_TYPE = "cellularNetworkType"; public static final String ATTRIBUTE_WIFI = "wifi"; + + /** + * Helper method for tracking gesture events + * + * @param projection Projection of the Map object + * @param gestureId Type of Gesture See {@see MapboxEvent#GESTURE_SINGLETAP MapboxEvent#GESTURE_DOUBLETAP MapboxEvent#GESTURE_TWO_FINGER_SINGLETAP MapboxEvent#GESTURE_QUICK_ZOOM MapboxEvent#GESTURE_PAN_START MapboxEvent#GESTURE_PINCH_START MapboxEvent#GESTURE_ROTATION_START MapboxEvent#GESTURE_PITCH_START} + * @param xCoordinate Original x screen coordinate at start of gesture + * @param yCoordinate Original y screen cooridnate at start of gesture + * @param zoom Zoom level to be registered + */ + public static void trackGestureEvent(@NonNull Projection projection, @NonNull String gestureId, float xCoordinate, float yCoordinate, double zoom) { + LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate)); + + // NaN and Infinite checks to prevent JSON errors at send to server time + if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) { + Timber.d("trackGestureEvent() has a NaN lat or lon. Returning."); + return; + } + + if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) { + Timber.d("trackGestureEvent() has an Infinite lat or lon. Returning."); + return; + } + + Hashtable<String, Object> evt = new Hashtable<>(); + evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK); + evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate()); + evt.put(MapboxEvent.KEY_GESTURE_ID, gestureId); + evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude()); + evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude()); + evt.put(MapboxEvent.KEY_ZOOM, zoom); + + MapboxEventManager.getMapboxEventManager().pushEvent(evt); + } + + /** + * Helper method for tracking DragEnd gesture event + * See {@see MapboxEvent#TYPE_MAP_DRAGEND} + * + * @param projection projection of the Map object. + * @param xCoordinate Original x screen coordinate at end of drag + * @param yCoordinate Orginal y screen coordinate at end of drag + * @param zoom Zoom level to be registered + */ + public static void trackGestureDragEndEvent(@NonNull Projection projection, float xCoordinate, float yCoordinate, double zoom) { + LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate)); + + // NaN and Infinite checks to prevent JSON errors at send to server time + if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) { + Timber.d("trackGestureDragEndEvent() has a NaN lat or lon. Returning."); + return; + } + + if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) { + Timber.d("trackGestureDragEndEvent() has an Infinite lat or lon. Returning."); + return; + } + + Hashtable<String, Object> evt = new Hashtable<>(); + evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_DRAGEND); + evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate()); + evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude()); + evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude()); + evt.put(MapboxEvent.KEY_ZOOM, zoom); + + MapboxEventManager.getMapboxEventManager().pushEvent(evt); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 11b5768d87..542038cbc7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' ext { - supportLibVersion = '25.0.0' + supportLibVersion = '25.0.1' } android { compileSdkVersion 25 - buildToolsVersion "25.0.0" + buildToolsVersion "25.0.1" defaultConfig { applicationId "com.mapbox.mapboxsdk.testapp" @@ -75,7 +75,7 @@ dependencies { // Testing dependencies testCompile 'junit:junit:4.12' - testCompile 'org.mockito:mockito-core:1.10.19' + testCompile 'org.mockito:mockito-core:2.2.27' androidTestCompile "com.android.support:support-annotations:${supportLibVersion}" androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5' diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java index da9c3f9c8f..427d7ff21d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapViewUtils.java @@ -7,31 +7,27 @@ import com.mapbox.mapboxsdk.geometry.LatLng; */ public class MapViewUtils { - public static void setDirection(MapView mapView, float direction) { - mapView.setBearing(direction); + public static void setDirection(MapboxMap mapboxMap, float direction) { + mapboxMap.getTransform().setBearing(direction); } - public static float getDirection(MapView mapView) { - return (float) mapView.getDirection(); + public static float getDirection(MapboxMap mapboxMap) { + return (float) mapboxMap.getTransform().getBearing(); } - public static void setTilt(MapView mapView, float tilt) { - mapView.setTilt((double) tilt); + public static void setTilt(MapboxMap mapboxMap, float tilt) { + mapboxMap.getTransform().setTilt((double) tilt); } - public static float getTilt(MapView mapView) { - return (float) mapView.getTilt(); + public static float getTilt(MapboxMap mapboxMap) { + return (float) mapboxMap.getTransform().getTilt(); } - public static void setLatLng(MapView mapView, LatLng latLng) { - mapView.setCenterCoordinate(latLng); + public static void setLatLng(MapboxMap mapboxMap, LatLng latLng) { + mapboxMap.getTransform().setCenterCoordinate(latLng); } - public static LatLng getLatLng(MapView mapView) { - return mapView.getCenterCoordinate(); - } - - public static int[] getContentPadding(MapView mapView) { - return new int[]{mapView.getContentPaddingLeft(), mapView.getContentPaddingTop(), mapView.getContentPaddingRight(), mapView.getContentPaddingBottom()}; + public static LatLng getLatLng(MapboxMap mapboxMap) { + return mapboxMap.getTransform().getCenterCoordinate(); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java new file mode 100644 index 0000000000..a8600668d8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -0,0 +1,624 @@ +package com.mapbox.mapboxsdk.maps; + +import android.graphics.Color; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.test.espresso.Espresso; +import android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.support.test.rule.ActivityTestRule; +import android.view.View; + +import com.mapbox.mapboxsdk.annotations.Annotation; +import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +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.constants.MapboxConstants; +import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; +import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource; + +import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import timber.log.Timber; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertNotNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * This test is responsible for testing the public API. + */ +public class MapboxMapTest { + + @Rule + public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class); + + private OnMapReadyIdlingResource idlingResource; + private EspressoTestActivity activity; + + @Before + public void beforeTest() { + activity = rule.getActivity(); + idlingResource = new OnMapReadyIdlingResource(activity); + Espresso.registerIdlingResources(idlingResource); + } + + @Test + @Ignore + public void testSanity() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("mapboxMap should not be null", mapboxMap); + } + + // + // MinZoomLevel + // + + @Test + @Ignore + public void testMinZoom() { + MapboxMap mapboxMap = activity.getMapboxMap(); + onView(withId(R.id.mapView)).perform(new MinZoomAction(mapboxMap)); + assertEquals("MinZoom should match", 10, mapboxMap.getMinZoom(), 0); + } + + @Test + @Ignore + public void testMaxZoom() { + MapboxMap mapboxMap = activity.getMapboxMap(); + double zoom = 10; + mapboxMap.setMaxZoom(zoom); + assertEquals("MaxZoom should match", zoom, mapboxMap.getMaxZoom(), 0); + } + + @Test + @Ignore + public void testInitialZoomLevels() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertEquals("MaxZoom should match", MapboxConstants.MAXIMUM_ZOOM, mapboxMap.getMaxZoom(), 0); + assertEquals("MinZoom should match", MapboxConstants.MINIMUM_ZOOM, mapboxMap.getMinZoom(), 0); + } + + // + // TrackingSettings + // + + @Test + @Ignore + public void testTrackingSettings() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("TrackingSettings should not be null", mapboxMap.getTrackingSettings()); + } + + // + // InfoWindow + // + + @Test + @Ignore + public void testConcurrentInfoWindowEnabled() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(true); + assertTrue("ConcurrentWindows should be true", mapboxMap.isAllowConcurrentMultipleOpenInfoWindows()); + } + + @Test + @Ignore + public void testConcurrentInfoWindowDisabled() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(false); + assertFalse("ConcurrentWindows should be false", mapboxMap.isAllowConcurrentMultipleOpenInfoWindows()); + } + + @Test + @Ignore + public void testInfoWindowAdapter() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MapboxMap.InfoWindowAdapter infoWindowAdapter = new MapboxMap.InfoWindowAdapter() { + @Nullable + @Override + public View getInfoWindow(@NonNull Marker marker) { + return null; + } + }; + mapboxMap.setInfoWindowAdapter(infoWindowAdapter); + assertEquals("InfoWindowAdpter should be the same", infoWindowAdapter, mapboxMap.getInfoWindowAdapter()); + } + + // + // Location + // + + @Test + @Ignore /* disabled due to enabling permissions during test #7177 */ + public void testMyLocationEnabled() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.setMyLocationEnabled(true); + assertTrue("MyLocationEnabled should be true", mapboxMap.isMyLocationEnabled()); + } + + @Test + @Ignore /* can't create handler inside thread that not called Looper.prepare() */ + public void testMyLocationDisabled() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.setMyLocationEnabled(false); + assertFalse("MyLocationEnabled should be false", mapboxMap.isMyLocationEnabled()); + } + + // + // setters/getters interfaces + // + + @Test + @Ignore + public void testFpsListener() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MapboxMap.OnFpsChangedListener fpsChangedListener = new MapboxMap.OnFpsChangedListener() { + @Override + public void onFpsChanged(double fps) { + + } + }; + mapboxMap.setOnFpsChangedListener(fpsChangedListener); + assertEquals("FpsListener should match", fpsChangedListener, mapboxMap.getOnFpsChangedListener()); + } + + @Test + @Ignore + public void testInfoWindowClickListener() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MapboxMap.OnInfoWindowClickListener clickListener = new MapboxMap.OnInfoWindowClickListener() { + @Override + public boolean onInfoWindowClick(@NonNull Marker marker) { + return false; + } + }; + mapboxMap.setOnInfoWindowClickListener(clickListener); + assertEquals("InfoWidowClickListener should match", clickListener, mapboxMap.getOnInfoWindowClickListener()); + } + + @Test + @Ignore + public void testInfoWindowCloseListener() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MapboxMap.OnInfoWindowCloseListener listener = new MapboxMap.OnInfoWindowCloseListener() { + @Override + public void onInfoWindowClose(Marker marker) { + + } + }; + mapboxMap.setOnInfoWindowCloseListener(listener); + assertEquals("InfoWindowCloseListener should match", listener, mapboxMap.getOnInfoWindowCloseListener()); + } + + @Test + @Ignore + public void testInfoWindowLongClickListener() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MapboxMap.OnInfoWindowLongClickListener listener = new MapboxMap.OnInfoWindowLongClickListener() { + @Override + public void onInfoWindowLongClick(Marker marker) { + + } + }; + mapboxMap.setOnInfoWindowLongClickListener(listener); + assertEquals("InfoWindowLongClickListener should match", listener, mapboxMap.getOnInfoWindowLongClickListener()); + } + + // + // Annotations + // + + @Test + @Ignore + public void testAddMarker() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker = mapboxMap.addMarker(markerOptions); + assertTrue("Marker should be contained", mapboxMap.getMarkers().contains(marker)); + } + + @Test(expected = InvalidMarkerPositionException.class) + @Ignore + public void testAddMarkerInvalidPosition() { + new MarkerOptions().getMarker(); + } + + @Test + @Ignore + public void testAddMarkers() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + MarkerOptions markerOptions1 = new MarkerOptions().position(new LatLng()).title("a"); + MarkerOptions markerOptions2 = new MarkerOptions().position(new LatLng()).title("b"); + markerList.add(markerOptions1); + markerList.add(markerOptions2); + List<Marker> markers = mapboxMap.addMarkers(markerList); + assertEquals("Markers size should be 2", 2, mapboxMap.getMarkers().size()); + assertTrue(mapboxMap.getMarkers().contains(markers.get(0))); + assertTrue(mapboxMap.getMarkers().contains(markers.get(1))); + } + + @Test + @Ignore + public void testAddMarkersEmpty() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + mapboxMap.addMarkers(markerList); + assertEquals("Markers size should be 0", 0, mapboxMap.getMarkers().size()); + } + + @Test + @Ignore + public void testAddMarkersSingleMarker() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + MarkerOptions markerOptions = new MarkerOptions().title("a").position(new LatLng()); + markerList.add(markerOptions); + List<Marker> markers = mapboxMap.addMarkers(markerList); + assertEquals("Markers size should be 1", 1, mapboxMap.getMarkers().size()); + assertTrue(mapboxMap.getMarkers().contains(markers.get(0))); + } + + @Test + @Ignore + public void testAddPolygon() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolygonOptions polygonOptions = new PolygonOptions().add(new LatLng()); + Polygon polygon = mapboxMap.addPolygon(polygonOptions); + assertTrue("Polygon should be contained", mapboxMap.getPolygons().contains(polygon)); + } + + @Test + @Ignore + public void testAddEmptyPolygon() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolygonOptions polygonOptions = new PolygonOptions(); + Polygon polygon = mapboxMap.addPolygon(polygonOptions); + assertTrue("Polygon should be ignored", !mapboxMap.getPolygons().contains(polygon)); + } + + @Test + @Ignore + public void testAddPolygons() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<PolygonOptions> polygonList = new ArrayList<>(); + PolygonOptions polygonOptions1 = new PolygonOptions().fillColor(Color.BLACK).add(new LatLng()); + PolygonOptions polygonOptions2 = new PolygonOptions().fillColor(Color.WHITE).add(new LatLng()); + PolygonOptions polygonOptions3 = new PolygonOptions(); + polygonList.add(polygonOptions1); + polygonList.add(polygonOptions2); + polygonList.add(polygonOptions3); + mapboxMap.addPolygons(polygonList); + assertEquals("Polygons size should be 2", 2, mapboxMap.getPolygons().size()); + assertTrue(mapboxMap.getPolygons().contains(polygonOptions1.getPolygon())); + assertTrue(mapboxMap.getPolygons().contains(polygonOptions2.getPolygon())); + assertTrue("Polygon should be ignored", !mapboxMap.getPolygons().contains(polygonOptions3.getPolygon())); + } + + @Test + @Ignore + public void addPolygonsEmpty() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.addPolygons(new ArrayList<PolygonOptions>()); + assertEquals("Polygons size should be 0", 0, mapboxMap.getPolygons().size()); + } + + @Test + @Ignore + public void addPolygonsSingle() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<PolygonOptions> polygonList = new ArrayList<>(); + PolygonOptions polygonOptions = new PolygonOptions().fillColor(Color.BLACK).add(new LatLng()); + polygonList.add(polygonOptions); + mapboxMap.addPolygons(polygonList); + assertEquals("Polygons size should be 1", 1, mapboxMap.getPolygons().size()); + assertTrue(mapboxMap.getPolygons().contains(polygonOptions.getPolygon())); + } + + @Test + @Ignore + public void testAddPolyline() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolylineOptions polylineOptions = new PolylineOptions().add(new LatLng()); + Polyline polyline = mapboxMap.addPolyline(polylineOptions); + assertTrue("Polyline should be contained", mapboxMap.getPolylines().contains(polyline)); + } + + @Test + @Ignore + public void testAddEmptyPolyline() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolylineOptions polylineOptions = new PolylineOptions(); + Polyline polyline = mapboxMap.addPolyline(polylineOptions); + assertTrue("Polyline should be ignored", !mapboxMap.getPolylines().contains(polyline)); + } + + @Test + @Ignore + public void testAddPolylines() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<PolylineOptions> polylineList = new ArrayList<>(); + PolylineOptions polygonOptions1 = new PolylineOptions().color(Color.BLACK).add(new LatLng()); + PolylineOptions polygonOptions2 = new PolylineOptions().color(Color.WHITE).add(new LatLng()); + PolylineOptions polygonOptions3 = new PolylineOptions(); + polylineList.add(polygonOptions1); + polylineList.add(polygonOptions2); + polylineList.add(polygonOptions3); + mapboxMap.addPolylines(polylineList); + assertEquals("Polygons size should be 2", 2, mapboxMap.getPolylines().size()); + assertTrue(mapboxMap.getPolylines().contains(polygonOptions1.getPolyline())); + assertTrue(mapboxMap.getPolylines().contains(polygonOptions2.getPolyline())); + assertTrue("Polyline should be ignored", !mapboxMap.getPolylines().contains(polygonOptions3.getPolyline())); + } + + @Test + @Ignore + public void testAddPolylinesEmpty() { + MapboxMap mapboxMap = activity.getMapboxMap(); + mapboxMap.addPolylines(new ArrayList<PolylineOptions>()); + assertEquals("Polygons size should be 0", 0, mapboxMap.getPolylines().size()); + } + + @Test + @Ignore + public void testAddPolylinesSingle() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<PolylineOptions> polylineList = new ArrayList<>(); + PolylineOptions polygonOptions = new PolylineOptions().color(Color.BLACK).add(new LatLng()); + polylineList.add(polygonOptions); + mapboxMap.addPolylines(polylineList); + assertEquals("Polygons size should be 1", 1, mapboxMap.getPolylines().size()); + assertTrue(mapboxMap.getPolylines().contains(polygonOptions.getPolyline())); + } + + @Test + @Ignore + public void testRemoveMarker() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker = mapboxMap.addMarker(markerOptions); + mapboxMap.removeMarker(marker); + assertTrue("Markers should be empty", mapboxMap.getMarkers().isEmpty()); + } + + @Test + @Ignore + public void testRemovePolygon() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolygonOptions polygonOptions = new PolygonOptions(); + Polygon polygon = mapboxMap.addPolygon(polygonOptions); + mapboxMap.removePolygon(polygon); + assertTrue("Polygons should be empty", mapboxMap.getPolylines().isEmpty()); + } + + @Test + @Ignore + public void testRemovePolyline() { + MapboxMap mapboxMap = activity.getMapboxMap(); + PolylineOptions polylineOptions = new PolylineOptions(); + Polyline polyline = mapboxMap.addPolyline(polylineOptions); + mapboxMap.removePolyline(polyline); + assertTrue("Polylines should be empty", mapboxMap.getPolylines().isEmpty()); + } + + @Test + @Ignore + public void testRemoveAnnotation() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker = mapboxMap.addMarker(markerOptions); + onView(withId(R.id.mapView)).perform(new RemoveAnnotationAction(marker, mapboxMap)); + assertTrue("Annotations should be empty", mapboxMap.getAnnotations().isEmpty()); + } + + @Test + @Ignore + public void testRemoveAnnotationById() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + mapboxMap.addMarker(markerOptions); + // id will always be 0 in unit tests + mapboxMap.removeAnnotation(0); + assertTrue("Annotations should be empty", mapboxMap.getAnnotations().isEmpty()); + } + + @Test + @Ignore + public void testRemoveAnnotations() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); + MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); + markerList.add(markerOptions1); + markerList.add(markerOptions2); + mapboxMap.addMarkers(markerList); + mapboxMap.removeAnnotations(); + assertTrue("Annotations should be empty", mapboxMap.getAnnotations().isEmpty()); + } + + @Test + @Ignore + public void testClear() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); + MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); + markerList.add(markerOptions1); + markerList.add(markerOptions2); + mapboxMap.addMarkers(markerList); + mapboxMap.clear(); + assertTrue("Annotations should be empty", mapboxMap.getAnnotations().isEmpty()); + } + + @Test + @Ignore + public void testRemoveAnnotationsByList() { + MapboxMap mapboxMap = activity.getMapboxMap(); + List<BaseMarkerOptions> markerList = new ArrayList<>(); + MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); + MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); + markerList.add(markerOptions1); + markerList.add(markerOptions2); + List<Marker> markers = mapboxMap.addMarkers(markerList); + Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng()).title("c")); + mapboxMap.removeAnnotations(markers); + assertTrue("Annotations should not be empty", mapboxMap.getAnnotations().size() == 1); + assertTrue("Marker should be contained", mapboxMap.getAnnotations().contains(marker)); + } + + @Test + @Ignore + public void testGetAnnotationById() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker initialMarker = mapboxMap.addMarker(markerOptions); + Marker retrievedMarker = (Marker) mapboxMap.getAnnotation(0); + assertEquals("Markers should match", initialMarker, retrievedMarker); + } + + @Test + @Ignore + public void testGetAnnotations() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("Annotations should be non null", mapboxMap.getAnnotations()); + } + + @Test + @Ignore + public void testGetMarkers() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("Markers should be non null", mapboxMap.getMarkers()); + } + + @Test + @Ignore + public void testGetPolygons() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("Polygons should be non null", mapboxMap.getPolygons()); + } + + @Test + @Ignore + public void testGetPolylines() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("Polylines should be non null", mapboxMap.getPolylines()); + } + + @Test + @Ignore + public void testGetSelectedMarkers() { + MapboxMap mapboxMap = activity.getMapboxMap(); + assertNotNull("Selected markers should be non null", mapboxMap.getSelectedMarkers()); + } + + @Test + @Ignore + public void testSelectMarker() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker = mapboxMap.addMarker(markerOptions); + mapboxMap.selectMarker(marker); + assertTrue("Marker should be contained", mapboxMap.getSelectedMarkers().contains(marker)); + } + + @Test + @Ignore + public void testDeselectMarker() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker = mapboxMap.addMarker(markerOptions); + mapboxMap.selectMarker(marker); + mapboxMap.deselectMarker(marker); + assertTrue("Selected markers should be empty", mapboxMap.getSelectedMarkers().isEmpty()); + } + + @Test + @Ignore + public void testDeselectMarkers() { + MapboxMap mapboxMap = activity.getMapboxMap(); + MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); + Marker marker1 = mapboxMap.addMarker(markerOptions); + Marker marker2 = mapboxMap.addMarker(markerOptions); + mapboxMap.selectMarker(marker1); + mapboxMap.selectMarker(marker2); + mapboxMap.deselectMarkers(); + assertTrue("Selected markers should be empty", mapboxMap.getSelectedMarkers().isEmpty()); + } + + @After + public void afterTest() { + Timber.e("@After test: unregister idle resource"); + Espresso.unregisterIdlingResources(idlingResource); + } + + private class MinZoomAction implements ViewAction { + + private MapboxMap mapboxMap; + + MinZoomAction(MapboxMap map) { + mapboxMap = map; + } + + @Override + public Matcher<View> getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return getClass().getSimpleName(); + } + + @Override + public void perform(UiController uiController, View view) { + mapboxMap.setMinZoom(10); + } + } + + private class RemoveAnnotationAction implements ViewAction { + + private Annotation annotation; + private MapboxMap mapboxMap; + + RemoveAnnotationAction(Annotation annotation, MapboxMap mapboxMap) { + this.annotation = annotation; + this.mapboxMap = mapboxMap; + } + + @Override + public Matcher<View> getConstraints() { + return isDisplayed(); + } + + @Override + public String getDescription() { + return getClass().getSimpleName(); + } + + @Override + public void perform(UiController uiController, View view) { + mapboxMap.removeAnnotation(annotation); + } + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java index 650c9dc834..36e943b7ff 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java @@ -19,6 +19,7 @@ import com.mapbox.mapboxsdk.testapp.utils.ViewUtils; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -44,6 +45,7 @@ public class MarkerTest { } @Test + @Ignore public void addMarkerTest() { ViewUtils.checkViewIsDisplayed(R.id.mapView); MapboxMap mapboxMap = rule.getActivity().getMapboxMap(); @@ -65,6 +67,7 @@ public class MarkerTest { } @Test + @Ignore public void showInfoWindowTest(){ ViewUtils.checkViewIsDisplayed(R.id.mapView); MapboxMap mapboxMap = rule.getActivity().getMapboxMap(); 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 d39b5dad96..09f707c4b5 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 @@ -110,7 +110,6 @@ 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); } } @@ -136,7 +135,6 @@ public class MarkerViewTest { @Override public void perform(UiController uiController, View view) { mapboxMap.selectMarker(marker); - mapboxMap.invalidate(); uiController.loopMainThreadForAtLeast(250); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java index 5e99cff936..73e3c8559f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java @@ -231,7 +231,7 @@ public class CameraAnimateTest { @Override public void perform(UiController uiController, View view) { mapboxMap.animateCamera(cameraUpdate); - uiController.loopMainThreadForAtLeast(MapboxConstants.ANIMATION_DURATION); + uiController.loopMainThreadForAtLeast(TestConstants.ANIMATION_TEST_TIME); } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java index 3782991e58..4f27703b18 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java @@ -231,7 +231,7 @@ public class CameraEaseTest { @Override public void perform(UiController uiController, View view) { mapboxMap.easeCamera(cameraUpdate); - uiController.loopMainThreadForAtLeast(MapboxConstants.ANIMATION_DURATION); + uiController.loopMainThreadForAtLeast(TestConstants.ANIMATION_TEST_TIME); } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalAPITest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalAPITest.java index 9bb30c0aa1..e180ab77b2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalAPITest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalAPITest.java @@ -54,9 +54,8 @@ public class CameraInternalAPITest { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); assertEquals("Default camera position should match default", cameraPosition, initialPosition); - MapView mapView = (MapView) activity.findViewById(R.id.mapView); - onView(withId(R.id.mapView)).perform(new BearingAction(mapView)); - assertEquals("Bearing should match", 45.1f, MapViewUtils.getDirection(mapView), TestConstants.BEARING_DELTA); + onView(withId(R.id.mapView)).perform(new BearingAction(mapboxMap)); + assertEquals("Bearing should match", 45.1f, MapViewUtils.getDirection(mapboxMap), TestConstants.BEARING_DELTA); } @Test @@ -69,9 +68,8 @@ public class CameraInternalAPITest { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); assertEquals("Default camera position should match default", cameraPosition, initialPosition); - MapView mapView = (MapView) activity.findViewById(R.id.mapView); - onView(withId(R.id.mapView)).perform(new TiltAction(mapView)); - assertEquals("Tilt should match", 40.0f, MapViewUtils.getTilt(mapView), TestConstants.TILT_DELTA); + onView(withId(R.id.mapView)).perform(new TiltAction(mapboxMap)); + assertEquals("Tilt should match", 40.0f, MapViewUtils.getTilt(mapboxMap), TestConstants.TILT_DELTA); } @Test @@ -84,10 +82,8 @@ public class CameraInternalAPITest { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); assertEquals("Default camera position should match default", cameraPosition, initialPosition); - MapView mapView = (MapView) activity.findViewById(R.id.mapView); - onView(withId(R.id.mapView)).perform(new LatLngAction(mapView)); - - LatLng centerCoordinate = MapViewUtils.getLatLng(mapView); + onView(withId(R.id.mapView)).perform(new LatLngAction(mapboxMap)); + LatLng centerCoordinate = MapViewUtils.getLatLng(mapboxMap); assertEquals("Latitude should match", 1.1f, centerCoordinate.getLatitude(), TestConstants.LAT_LNG_DELTA); assertEquals("Longitude should match", 2.2f, centerCoordinate.getLongitude(), TestConstants.LAT_LNG_DELTA); } @@ -99,10 +95,10 @@ public class CameraInternalAPITest { private class BearingAction implements ViewAction { - private MapView mapView; + private MapboxMap mapboxMap; - BearingAction(MapView mapView) { - this.mapView = mapView; + BearingAction(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; } @Override @@ -117,16 +113,16 @@ public class CameraInternalAPITest { @Override public void perform(UiController uiController, View view) { - MapViewUtils.setDirection(mapView, -45.1f); + MapViewUtils.setDirection(mapboxMap, -45.1f); } } private class TiltAction implements ViewAction { - private MapView mapView; + private MapboxMap mapboxMap; - TiltAction(MapView mapView) { - this.mapView = mapView; + TiltAction(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; } @Override @@ -141,16 +137,16 @@ public class CameraInternalAPITest { @Override public void perform(UiController uiController, View view) { - MapViewUtils.setTilt(mapView, 40.0f); + MapViewUtils.setTilt(mapboxMap, 40.0f); } } private class LatLngAction implements ViewAction { - private MapView mapView; + private MapboxMap mapboxMap; - LatLngAction(MapView mapView) { - this.mapView = mapView; + LatLngAction(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; } @Override @@ -165,7 +161,7 @@ public class CameraInternalAPITest { @Override public void perform(UiController uiController, View view) { - MapViewUtils.setLatLng(mapView, new LatLng(1.1, 2.2)); + MapViewUtils.setLatLng(mapboxMap, new LatLng(1.1, 2.2)); } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java index 67556e49fb..fdbb92ac56 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java @@ -1,7 +1,11 @@ package com.mapbox.mapboxsdk.testapp.utils; +import com.mapbox.mapboxsdk.constants.MapboxConstants; + public class TestConstants { + public static final long ANIMATION_TEST_TIME = MapboxConstants.ANIMATION_DURATION * 2; + public static final double LAT_LNG_DELTA_LARGE = 0.1; public static final double LAT_LNG_DELTA = 0.01; public static final double BEARING_DELTA = 0.1; @@ -11,5 +15,4 @@ public class TestConstants { public static final String TEXT_MARKER_TEXT = "Text"; public static final String TEXT_MARKER_TITLE = "Marker"; public static final String TEXT_MARKER_SNIPPET = "Snippet"; - } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java index 7099b5728a..2bb1a5b3d5 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java @@ -140,13 +140,15 @@ public class MarkerViewActivity extends AppCompatActivity { markerViewManager.addMarkerViewAdapter(new CountryAdapter(MarkerViewActivity.this, mapboxMap)); markerViewManager.addMarkerViewAdapter(new TextAdapter(MarkerViewActivity.this, mapboxMap)); + final ViewGroup markerViewContainer = markerViewManager.getMarkerViewContainer(); + // add a change listener to validate the size of amount of child views mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() { @Override public void onMapChanged(@MapView.MapChange int change) { if (change == MapView.REGION_IS_CHANGING || change == MapView.REGION_DID_CHANGE) { if (!markerViewManager.getMarkerViewAdapters().isEmpty() && viewCountView != null) { - viewCountView.setText("ViewCache size " + mapView.getMarkerViewContainer().getChildCount()); + viewCountView.setText("ViewCache size " + markerViewContainer.getChildCount()); } } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java index 366377ca62..cc080eb5f0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java @@ -42,6 +42,9 @@ public class OfflineActivity extends AppCompatActivity public static final String JSON_CHARSET = "UTF-8"; public static final String JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME"; + // Style URL + public static final String STYLE_URL = Style.MAPBOX_STREETS; + /* * UI elements */ @@ -82,7 +85,7 @@ public class OfflineActivity extends AppCompatActivity // Set up map mapView = (MapView) findViewById(R.id.mapView); - mapView.setStyleUrl(Style.MAPBOX_STREETS); + mapView.setStyleUrl(STYLE_URL); mapView.onCreate(savedInstanceState); mapView.getMapAsync(new OnMapReadyCallback() { @Override @@ -242,13 +245,12 @@ public class OfflineActivity extends AppCompatActivity startProgress(); // Definition - String styleUrl = mapboxMap.getStyleUrl(); LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds; double minZoom = mapboxMap.getCameraPosition().zoom; double maxZoom = mapboxMap.getMaxZoom(); float pixelRatio = this.getResources().getDisplayMetrics().density; OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition( - styleUrl, bounds, minZoom, maxZoom, pixelRatio); + STYLE_URL, bounds, minZoom, maxZoom, pixelRatio); // Sample way of encoding metadata from a JSONObject byte[] metadata = OfflineUtils.convertRegionName(regionName); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index dbde9a4420..1f69f7bcd7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -179,13 +179,6 @@ public class MapboxMapOptionsTest { } @Test - public void testParceable() { - MapboxMapOptions options = new MapboxMapOptions().camera(new CameraPosition.Builder().build()).styleUrl("s").accessToken("a").debugActive(true).compassMargins(new int[]{0, 1, 2, 3}); - MapboxMapOptions parceled = (MapboxMapOptions) MockParcel.obtain(options); - assertEquals(options, parceled); - } - - @Test public void testAccessToken() { assertNull(new MapboxMapOptions().getAccessToken()); assertEquals("test", new MapboxMapOptions().accessToken("test").getAccessToken()); 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 deleted file mode 100644 index 6371ddc2b8..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ /dev/null @@ -1,542 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import android.graphics.Color; - -import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; -import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerOptions; -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.exceptions.InvalidMarkerPositionException; -import com.mapbox.mapboxsdk.geometry.LatLng; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; - -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.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class MapboxMapTest { - - private MapboxMap mMapboxMap; - - @InjectMocks - MapView mMapView = mock(MapView.class); - - @Mock - MapboxMap.OnMarkerClickListener mOnMarkerClickListener; - - @Mock - MapboxMap.OnCameraChangeListener mOnCameraChangeListener; - - @Mock - MapboxMap.InfoWindowAdapter mInfoWindowAdapter; - - @Mock - MapboxMap.OnScrollListener mScrollListener; - - @Mock - MapboxMap.OnFlingListener mFlingListener; - - @Mock - MapboxMap.OnFpsChangedListener mFpsChangedListener; - - @Mock - MapboxMap.OnInfoWindowClickListener mWindowClickListener; - - @Mock - MapboxMap.OnInfoWindowCloseListener mWindowCloseListener; - - @Mock - MapboxMap.OnInfoWindowLongClickListener mWindowLongClickListener; - - @Mock - MapboxMap.OnMyLocationChangeListener mLocationChangeListener; - - @Mock - MapboxMap.OnMyLocationTrackingModeChangeListener mMyLocationTrackingModeChangeListener; - - @Mock - MapboxMap.OnMyBearingTrackingModeChangeListener mMyBearingTrackingModeChangeListener; - - @Mock - IconManager iconManager; - - @Before - public void beforeTest() { - MockitoAnnotations.initMocks(this); - mMapboxMap = new MapboxMap(mMapView, iconManager); - } - - @Test - public void testSanity() { - assertNotNull("mMapboxMap should not be null", mMapboxMap); - } - - @Test - public void testMock() { - assertNotNull("mMapView should be mocked", mMapView); - } - - @Test - public void testGetMapView() { - assertNotNull("MapView should be non null", mMapboxMap.getMapView()); - } - - // - // UiSettings - // - - @Test - public void testUiSettings() { - assertNotNull("UiSettings should not be null", mMapboxMap.getUiSettings()); - } - - // - // MinZoomLevel - // - - @Test - public void testMinZoom() { - double zoom = 10; - mMapboxMap.setMinZoom(zoom); - assertEquals("MinZoom should match", zoom, mMapboxMap.getMinZoom(), 0); - } - - @Test - public void testMaxZoom() { - double zoom = 10; - mMapboxMap.setMaxZoom(zoom); - assertEquals("MaxZoom should match", zoom, mMapboxMap.getMaxZoom(), 0); - } - - @Test - public void testInitialZoomLevels() { - assertEquals("MaxZoom should match", 0, mMapboxMap.getMaxZoom(), 0); - assertEquals("MinZoom should match", 0, mMapboxMap.getMinZoom(), 0); - } - - // - // TrackingSettings - // - - @Test - public void testTrackingSettings() { - assertNotNull("TrackingSettings should not be null", mMapboxMap.getTrackingSettings()); - } - - // - // Projection - // - - @Test - public void testProjection() { - assertNotNull("Projection should not be null", mMapboxMap.getProjection()); - } - - // - // InfoWindow - // - - @Test - public void testConcurrentInfoWindowEnabled() { - mMapboxMap.setAllowConcurrentMultipleOpenInfoWindows(true); - assertTrue("ConcurrentWindows should be true", mMapboxMap.isAllowConcurrentMultipleOpenInfoWindows()); - } - - @Test - public void testConcurrentInfoWindowDisabled() { - mMapboxMap.setAllowConcurrentMultipleOpenInfoWindows(false); - assertFalse("ConcurrentWindows should be false", mMapboxMap.isAllowConcurrentMultipleOpenInfoWindows()); - } - - @Test - public void testInfoWindowAdapter() { - mMapboxMap.setInfoWindowAdapter(mInfoWindowAdapter); - assertEquals("InfoWindowAdpter should be the same", mInfoWindowAdapter, mMapboxMap.getInfoWindowAdapter()); - } - - // - // Location - // - - @Test - public void testMyLocationEnabled() { - when(mMapView.isPermissionsAccepted()).thenReturn(true); - mMapboxMap.setMyLocationEnabled(true); - assertTrue("MyLocationEnabled should be true", mMapboxMap.isMyLocationEnabled()); - - } - - @Test - public void testMyLocationDisabled() { - when(mMapView.isPermissionsAccepted()).thenReturn(true); - mMapboxMap.setMyLocationEnabled(false); - assertFalse("MyLocationEnabled should be false", mMapboxMap.isMyLocationEnabled()); - } - - // - // setters/getters interfaces - // - - @Test - public void testScrollListener() { - mMapboxMap.setOnScrollListener(mScrollListener); - assertEquals("ScrollListener should match", mScrollListener, mMapboxMap.getOnScrollListener()); - } - - @Test - public void testFlingListener() { - mMapboxMap.setOnFlingListener(mFlingListener); - assertEquals("FlingListener should match", mFlingListener, mMapboxMap.getOnFlingListener()); - } - - @Test - public void testFpsListener() { - mMapboxMap.setOnFpsChangedListener(mFpsChangedListener); - assertEquals("FpsListener should match", mFpsChangedListener, mMapboxMap.getOnFpsChangedListener()); - } - - @Test - public void testInfoWindowClickListener() { - mMapboxMap.setOnInfoWindowClickListener(mWindowClickListener); - assertEquals("InfoWidowClickListener should match", mWindowClickListener, mMapboxMap.getOnInfoWindowClickListener()); - } - - @Test - public void testInfoWindowCloseListener() { - mMapboxMap.setOnInfoWindowCloseListener(mWindowCloseListener); - assertEquals("InfoWindowCloseListener should match", mWindowCloseListener, mMapboxMap.getOnInfoWindowCloseListener()); - } - - @Test - public void testInfoWindowLongClickListener() { - mMapboxMap.setOnInfoWindowLongClickListener(mWindowLongClickListener); - assertEquals("InfoWindowLongClickListener should match", mWindowLongClickListener, mMapboxMap.getOnInfoWindowLongClickListener()); - } - - @Test - public void testOnBearingTrackingModeChangeListener() { - mMapboxMap.setOnMyBearingTrackingModeChangeListener(mMyBearingTrackingModeChangeListener); - assertEquals("MyBearingTrackingChangeListerner should match", mMyBearingTrackingModeChangeListener, mMapboxMap.getOnMyBearingTrackingModeChangeListener()); - } - - @Test - public void testOnLocationTrackingModeChangeListener() { - mMapboxMap.setOnMyLocationTrackingModeChangeListener(mMyLocationTrackingModeChangeListener); - assertEquals("MyLocationTrackigChangeListener should match", mMyLocationTrackingModeChangeListener, mMapboxMap.getOnMyLocationTrackingModeChangeListener()); - } - - // - // Annotations - // - - @Test - public void testAddMarker() { - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker = mMapboxMap.addMarker(markerOptions); - assertTrue("Marker should be contained", mMapboxMap.getMarkers().contains(marker)); - } - - @Test(expected = InvalidMarkerPositionException.class) - public void testAddMarkerInvalidPosition() { - new MarkerOptions().getMarker(); - } - - @Test - public void testAddMarkers() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - MarkerOptions markerOptions1 = new MarkerOptions().position(new LatLng()).title("a"); - MarkerOptions markerOptions2 = new MarkerOptions().position(new LatLng()).title("b"); - markerList.add(markerOptions1); - markerList.add(markerOptions2); - List<Marker> markers = mMapboxMap.addMarkers(markerList); - assertEquals("Markers size should be 2", 2, mMapboxMap.getMarkers().size()); - assertTrue(mMapboxMap.getMarkers().contains(markers.get(0))); - assertTrue(mMapboxMap.getMarkers().contains(markers.get(1))); - } - - @Test - public void testAddMarkersEmpty() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - mMapboxMap.addMarkers(markerList); - assertEquals("Markers size should be 0", 0, mMapboxMap.getMarkers().size()); - } - - @Test - public void testAddMarkersSingleMarker() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - MarkerOptions markerOptions = new MarkerOptions().title("a").position(new LatLng()); - markerList.add(markerOptions); - List<Marker> markers = mMapboxMap.addMarkers(markerList); - assertEquals("Markers size should be 1", 1, mMapboxMap.getMarkers().size()); - assertTrue(mMapboxMap.getMarkers().contains(markers.get(0))); - } - - @Test - public void testAddPolygon() { - PolygonOptions polygonOptions = new PolygonOptions().add(new LatLng()); - Polygon polygon = mMapboxMap.addPolygon(polygonOptions); - assertTrue("Polygon should be contained", mMapboxMap.getPolygons().contains(polygon)); - } - - @Test - public void testAddEmptyPolygon() { - PolygonOptions polygonOptions = new PolygonOptions(); - Polygon polygon = mMapboxMap.addPolygon(polygonOptions); - assertTrue("Polygon should be ignored", !mMapboxMap.getPolygons().contains(polygon)); - } - - @Test - public void testAddPolygons() { - List<PolygonOptions> polygonList = new ArrayList<>(); - PolygonOptions polygonOptions1 = new PolygonOptions().fillColor(Color.BLACK).add(new LatLng()); - PolygonOptions polygonOptions2 = new PolygonOptions().fillColor(Color.WHITE).add(new LatLng()); - PolygonOptions polygonOptions3 = new PolygonOptions(); - polygonList.add(polygonOptions1); - polygonList.add(polygonOptions2); - polygonList.add(polygonOptions3); - mMapboxMap.addPolygons(polygonList); - assertEquals("Polygons size should be 2", 2, mMapboxMap.getPolygons().size()); - assertTrue(mMapboxMap.getPolygons().contains(polygonOptions1.getPolygon())); - assertTrue(mMapboxMap.getPolygons().contains(polygonOptions2.getPolygon())); - assertTrue("Polygon should be ignored", !mMapboxMap.getPolygons().contains(polygonOptions3.getPolygon())); - } - - @Test - public void addPolygonsEmpty() { - mMapboxMap.addPolygons(new ArrayList<PolygonOptions>()); - assertEquals("Polygons size should be 0", 0, mMapboxMap.getPolygons().size()); - } - - @Test - public void addPolygonsSingle() { - List<PolygonOptions> polygonList = new ArrayList<>(); - PolygonOptions polygonOptions = new PolygonOptions().fillColor(Color.BLACK).add(new LatLng()); - polygonList.add(polygonOptions); - mMapboxMap.addPolygons(polygonList); - assertEquals("Polygons size should be 1", 1, mMapboxMap.getPolygons().size()); - assertTrue(mMapboxMap.getPolygons().contains(polygonOptions.getPolygon())); - } - - @Test - public void testAddPolyline() { - PolylineOptions polylineOptions = new PolylineOptions().add(new LatLng()); - Polyline polyline = mMapboxMap.addPolyline(polylineOptions); - assertTrue("Polyline should be contained", mMapboxMap.getPolylines().contains(polyline)); - } - - @Test - public void testAddEmptyPolyline() { - PolylineOptions polylineOptions = new PolylineOptions(); - Polyline polyline = mMapboxMap.addPolyline(polylineOptions); - assertTrue("Polyline should be ignored", !mMapboxMap.getPolylines().contains(polyline)); - } - - @Test - public void testAddPolylines() { - List<PolylineOptions> polylineList = new ArrayList<>(); - PolylineOptions polygonOptions1 = new PolylineOptions().color(Color.BLACK).add(new LatLng()); - PolylineOptions polygonOptions2 = new PolylineOptions().color(Color.WHITE).add(new LatLng()); - PolylineOptions polygonOptions3 = new PolylineOptions(); - polylineList.add(polygonOptions1); - polylineList.add(polygonOptions2); - polylineList.add(polygonOptions3); - mMapboxMap.addPolylines(polylineList); - assertEquals("Polygons size should be 2", 2, mMapboxMap.getPolylines().size()); - assertTrue(mMapboxMap.getPolylines().contains(polygonOptions1.getPolyline())); - assertTrue(mMapboxMap.getPolylines().contains(polygonOptions2.getPolyline())); - assertTrue("Polyline should be ignored", !mMapboxMap.getPolylines().contains(polygonOptions3.getPolyline())); - } - - @Test - public void testAddPolylinesEmpty() { - mMapboxMap.addPolylines(new ArrayList<PolylineOptions>()); - assertEquals("Polygons size should be 0", 0, mMapboxMap.getPolylines().size()); - } - - @Test - public void testAddPolylinesSingle() { - List<PolylineOptions> polylineList = new ArrayList<>(); - PolylineOptions polygonOptions = new PolylineOptions().color(Color.BLACK).add(new LatLng()); - polylineList.add(polygonOptions); - mMapboxMap.addPolylines(polylineList); - assertEquals("Polygons size should be 1", 1, mMapboxMap.getPolylines().size()); - assertTrue(mMapboxMap.getPolylines().contains(polygonOptions.getPolyline())); - } - - @Test - public void testRemoveMarker() { - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker = mMapboxMap.addMarker(markerOptions); - mMapboxMap.removeMarker(marker); - assertTrue("Markers should be empty", mMapboxMap.getMarkers().isEmpty()); - } - - @Test - public void testRemovePolygon() { - PolygonOptions polygonOptions = new PolygonOptions(); - Polygon polygon = mMapboxMap.addPolygon(polygonOptions); - mMapboxMap.removePolygon(polygon); - assertTrue("Polygons should be empty", mMapboxMap.getPolylines().isEmpty()); - } - - @Test - public void testRemovePolyline() { - PolylineOptions polylineOptions = new PolylineOptions(); - Polyline polyline = mMapboxMap.addPolyline(polylineOptions); - mMapboxMap.removePolyline(polyline); - assertTrue("Polylines should be empty", mMapboxMap.getPolylines().isEmpty()); - } - - @Test - public void testRemoveAnnotation() { - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker = mMapboxMap.addMarker(markerOptions); - mMapboxMap.removeAnnotation(marker); - assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty()); - } - - @Test - public void testRemoveAnnotationById() { - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - mMapboxMap.addMarker(markerOptions); - // id will always be 0 in unit tests - mMapboxMap.removeAnnotation(0); - assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty()); - } - - @Test - public void testRemoveAnnotations() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); - MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); - markerList.add(markerOptions1); - markerList.add(markerOptions2); - mMapboxMap.addMarkers(markerList); - mMapboxMap.removeAnnotations(); - assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty()); - } - - @Test - public void testClear() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); - MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); - markerList.add(markerOptions1); - markerList.add(markerOptions2); - mMapboxMap.addMarkers(markerList); - mMapboxMap.clear(); - assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty()); - } - - @Test - public void testRemoveAnnotationsByList() { - List<BaseMarkerOptions> markerList = new ArrayList<>(); - MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng()); - MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng()); - markerList.add(markerOptions1); - markerList.add(markerOptions2); - List<Marker> markers = mMapboxMap.addMarkers(markerList); - Marker marker = mMapboxMap.addMarker(new MarkerOptions().position(new LatLng()).title("c")); - mMapboxMap.removeAnnotations(markers); - assertTrue("Annotations should not be empty", mMapboxMap.getAnnotations().size() == 1); - assertTrue("Marker should be contained", mMapboxMap.getAnnotations().contains(marker)); - } - - @Test - public void testGetAnnotationById() { - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker initialMarker = mMapboxMap.addMarker(markerOptions); - Marker retrievedMarker = (Marker) mMapboxMap.getAnnotation(0); - assertEquals("Markers should match", initialMarker, retrievedMarker); - } - - @Test - public void testGetAnnotations() { - assertNotNull("Annotations should be non null", mMapboxMap.getAnnotations()); - } - - @Test - public void testGetMarkers() { - assertNotNull("Markers should be non null", mMapboxMap.getMarkers()); - } - - @Test - public void testGetPolygons() { - assertNotNull("Polygons should be non null", mMapboxMap.getPolygons()); - } - - @Test - public void testGetPolylines() { - assertNotNull("Polylines should be non null", mMapboxMap.getPolylines()); - } - - @Test - public void testGetSelectedMarkers() { - assertNotNull("Selected markers should be non null", mMapboxMap.getSelectedMarkers()); - } - - @Test - public void testSelectMarker() { - mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener); - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker = mMapboxMap.addMarker(markerOptions); - when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true); - mMapboxMap.selectMarker(marker); - assertTrue("Marker should be contained", mMapboxMap.getSelectedMarkers().contains(marker)); - } - - @Test - public void testDeselectMarker() { - mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener); - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker = mMapboxMap.addMarker(markerOptions); - when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true); - mMapboxMap.selectMarker(marker); - mMapboxMap.deselectMarker(marker); - assertTrue("Selected markers should be empty", mMapboxMap.getSelectedMarkers().isEmpty()); - } - - @Test - public void testDeselectMarkers() { - mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener); - MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()); - Marker marker1 = mMapboxMap.addMarker(markerOptions); - Marker marker2 = mMapboxMap.addMarker(markerOptions); - when(mOnMarkerClickListener.onMarkerClick(marker1)).thenReturn(true); - when(mOnMarkerClickListener.onMarkerClick(marker2)).thenReturn(true); - mMapboxMap.selectMarker(marker1); - mMapboxMap.selectMarker(marker2); - mMapboxMap.deselectMarkers(); - assertTrue("Selected markers should be empty", mMapboxMap.getSelectedMarkers().isEmpty()); - } - - // - // OnMarkerClick interface - // - - @Test - public void testOnMarkerClick() { - mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener); - Marker marker = new MarkerOptions().position(new LatLng()).getMarker(); - when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true); - mMapboxMap.selectMarker(marker); - verify(mOnMarkerClickListener, times(1)).onMarkerClick(marker); - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/ProjectionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/ProjectionTest.java deleted file mode 100644 index fac06de16b..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/ProjectionTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; - -public class ProjectionTest { - - @InjectMocks - MapView mMapView = mock(MapView.class); - - @Before - public void beforeTest() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testSanity() { - Projection projection = new Projection(mMapView); - assertNotNull("projection should not be null", projection); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java index 266bbadd95..21a05d2201 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java @@ -2,7 +2,9 @@ package com.mapbox.mapboxsdk.maps; import com.mapbox.mapboxsdk.constants.MyBearingTracking; import com.mapbox.mapboxsdk.constants.MyLocationTracking; +import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; +import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; @@ -14,38 +16,46 @@ import static org.mockito.Mockito.mock; public class TrackingSettingsTest { @InjectMocks - MapView mMapView = mock(MapView.class); + MyLocationView myLocationView = mock(MyLocationView.class); + + @InjectMocks + UiSettings uiSettings = mock(UiSettings.class); + + @InjectMocks + FocalPointChangeListener focalPointChangeListener = mock(FocalPointChangeListener.class); + + private TrackingSettings trackingSettings; + + @Before + public void beforeTest(){ + trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointChangeListener); + } @Test public void testSanity() { - TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView)); assertNotNull("trackingsettings should not be null", trackingSettings); } @Test public void testMyLocationTrackingMode() { - TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView)); trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); assertEquals("MyLocationTrackingMode should match", MyLocationTracking.TRACKING_FOLLOW, trackingSettings.getMyLocationTrackingMode()); } @Test public void testMyBearingTrackingMode() { - TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView)); trackingSettings.setMyBearingTrackingMode(MyBearingTracking.COMPASS); assertEquals("MyLocationTrackingMode should match", MyBearingTracking.COMPASS, trackingSettings.getMyBearingTrackingMode()); } @Test public void testDismissTrackingModesOnGesture() { - TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView)); trackingSettings.setDismissTrackingOnGesture(false); assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isDismissTrackingOnGesture()); } @Test - public void testValidateGesturesForTrackingModes(){ - TrackingSettings trackingSettings = new TrackingSettings(mMapView, new UiSettings(mMapView)); + public void testValidateGesturesForTrackingModes() { trackingSettings.setDismissTrackingOnGesture(false); trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW); assertFalse("DismissTrackingOnGesture should be false", trackingSettings.isDismissTrackingOnGesture()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java index 14fc84723d..741929b814 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java @@ -1,6 +1,11 @@ package com.mapbox.mapboxsdk.maps; import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.mapbox.mapboxsdk.maps.widgets.CompassView; import org.junit.Before; import org.junit.Test; @@ -16,13 +21,28 @@ import static org.mockito.Mockito.when; public class UiSettingsTest { @InjectMocks - MapView mMapView = mock(MapView.class); + Projection projection = mock(Projection.class); + + @InjectMocks + FocalPointChangeListener focalPointChangeListener = mock(FocalPointChangeListener.class); + + @InjectMocks + CompassView compassView = mock(CompassView.class); + + @InjectMocks + ImageView imageView = mock(ImageView.class); + + @InjectMocks + ImageView logoView = mock(ImageView.class); + + @InjectMocks + FrameLayout.LayoutParams layoutParams = mock(FrameLayout.LayoutParams.class); - UiSettings uiSettings; + private UiSettings uiSettings; @Before public void beforeTest() { - uiSettings = new UiSettings(mMapView); + uiSettings = new UiSettings(projection, focalPointChangeListener, compassView, imageView, logoView); } @Test @@ -32,6 +52,7 @@ public class UiSettingsTest { @Test public void testCompassEnabled() { + when(compassView.isEnabled()).thenReturn(true); uiSettings.setCompassEnabled(true); assertEquals("Compass should be enabled", true, uiSettings.isCompassEnabled()); } @@ -44,12 +65,20 @@ public class UiSettingsTest { @Test public void testCompassGravity() { - uiSettings.setCompassGravity(Gravity.LEFT); - assertEquals("Compass gravity should be same", Gravity.LEFT, uiSettings.getCompassGravity()); + when(compassView.getLayoutParams()).thenReturn(layoutParams); + layoutParams.gravity = Gravity.START; + uiSettings.setCompassGravity(Gravity.START); + assertEquals("Compass gravity should be same", Gravity.START, uiSettings.getCompassGravity()); } @Test public void testCompassMargins() { + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); + when(compassView.getLayoutParams()).thenReturn(layoutParams); + layoutParams.leftMargin = 1; + layoutParams.topMargin = 2; + layoutParams.rightMargin = 3; + layoutParams.bottomMargin = 4; uiSettings.setCompassMargins(1, 2, 3, 4); assertTrue("Compass margin left should be same", uiSettings.getCompassMarginLeft() == 1); assertTrue("Compass margin top should be same", uiSettings.getCompassMarginTop() == 2); @@ -58,9 +87,11 @@ public class UiSettingsTest { } @Test - public void testCompassFadeWhenFacingNorth(){ + public void testCompassFadeWhenFacingNorth() { + when(compassView.isFadeCompassViewFacingNorth()).thenReturn(true); assertTrue("Compass should fade when facing north by default.", uiSettings.isCompassFadeWhenFacingNorth()); uiSettings.setCompassFadeFacingNorth(false); + when(compassView.isFadeCompassViewFacingNorth()).thenReturn(false); assertFalse("Compass fading should be disabled", uiSettings.isCompassFadeWhenFacingNorth()); } @@ -72,18 +103,27 @@ public class UiSettingsTest { @Test public void testLogoDisabled() { + when(logoView.getVisibility()).thenReturn(View.GONE); uiSettings.setLogoEnabled(false); assertEquals("Logo should be disabled", false, uiSettings.isLogoEnabled()); } @Test public void testLogoGravity() { - uiSettings.setLogoGravity(Gravity.RIGHT); - assertEquals("Logo gravity should be same", Gravity.RIGHT, uiSettings.getLogoGravity()); + layoutParams.gravity = Gravity.END; + when(logoView.getLayoutParams()).thenReturn(layoutParams); + uiSettings.setLogoGravity(Gravity.END); + assertEquals("Logo gravity should be same", Gravity.END, uiSettings.getLogoGravity()); } @Test public void testLogoMargins() { + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); + when(logoView.getLayoutParams()).thenReturn(layoutParams); + layoutParams.leftMargin = 1; + layoutParams.topMargin = 2; + layoutParams.rightMargin = 3; + layoutParams.bottomMargin = 4; uiSettings.setLogoMargins(1, 2, 3, 4); assertTrue("Compass margin left should be same", uiSettings.getLogoMarginLeft() == 1); assertTrue("Compass margin top should be same", uiSettings.getLogoMarginTop() == 2); @@ -93,24 +133,34 @@ public class UiSettingsTest { @Test public void testAttributionEnabled() { + when(imageView.getVisibility()).thenReturn(View.VISIBLE); uiSettings.setAttributionEnabled(true); assertEquals("Attribution should be enabled", true, uiSettings.isAttributionEnabled()); } @Test public void testAttributionDisabled() { + when(imageView.getVisibility()).thenReturn(View.GONE); uiSettings.setAttributionEnabled(false); - assertEquals("Attribution should be disabled", false, uiSettings.isLogoEnabled()); + assertEquals("Attribution should be disabled", false, uiSettings.isAttributionEnabled()); } @Test public void testAttributionGravity() { - uiSettings.setAttributionGravity(Gravity.RIGHT); - assertEquals("Attribution gravity should be same", Gravity.RIGHT, uiSettings.getAttributionGravity()); + when(imageView.getLayoutParams()).thenReturn(layoutParams); + layoutParams.gravity = Gravity.END; + uiSettings.setAttributionGravity(Gravity.END); + assertEquals("Attribution gravity should be same", Gravity.END, uiSettings.getAttributionGravity()); } @Test public void testAttributionMargins() { + when(imageView.getLayoutParams()).thenReturn(layoutParams); + when(projection.getContentPadding()).thenReturn(new int[]{0, 0, 0, 0}); + layoutParams.leftMargin = 1; + layoutParams.topMargin = 2; + layoutParams.rightMargin = 3; + layoutParams.bottomMargin = 4; uiSettings.setAttributionMargins(1, 2, 3, 4); assertTrue("Attribution margin left should be same", uiSettings.getAttributionMarginLeft() == 1); assertTrue("Attribution margin top should be same", uiSettings.getAttributionMarginTop() == 2); @@ -287,21 +337,4 @@ public class UiSettingsTest { assertEquals("Zoom gesture should be disabled", false, uiSettings.isZoomGesturesEnabled()); assertEquals("Scroll gesture should be disabled", false, uiSettings.isScrollGesturesEnabled()); } - - @Test - public void testInvalidate() { - uiSettings.invalidate(); - } - - @Test - public void testHeight() { - when(mMapView.getMeasuredHeight()).thenReturn(1); - assertEquals("height should be same as mocked instance", 1, uiSettings.getHeight(), 0); - } - - @Test - public void testWidth() { - when(mMapView.getMeasuredWidth()).thenReturn(1); - assertEquals("width should be same as mocked instance", 1, uiSettings.getWidth(), 0); - } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java index fd70308931..550040338f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java @@ -3,7 +3,8 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.graphics.Color; import android.graphics.drawable.Drawable; -import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.mapboxsdk.maps.TrackingSettings; import org.junit.Before; import org.junit.Test; @@ -21,16 +22,19 @@ import static org.mockito.Mockito.when; public class MyLocationViewSettingsTest { @InjectMocks - MapView mMapView = mock(MapView.class); + Projection projection = mock(Projection.class); @InjectMocks MyLocationView myLocationView = mock(MyLocationView.class); - MyLocationViewSettings locationViewSettings; + @InjectMocks + TrackingSettings trackingSettings = mock(TrackingSettings.class); + + private MyLocationViewSettings locationViewSettings; @Before public void beforeTest() { - locationViewSettings = new MyLocationViewSettings(mMapView, myLocationView); + locationViewSettings = new MyLocationViewSettings(projection, myLocationView, trackingSettings); } @Test @@ -81,3 +85,4 @@ public class MyLocationViewSettingsTest { } } + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..ca6ee9cea8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline
\ No newline at end of file diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 5471fb5508..5182e268f3 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -431,6 +431,12 @@ void nativeSetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, j nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url)); } +jni::jstring* nativeGetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr){ + assert(nativeMapViewPtr != 0); + NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); + return std_string_to_jstring(env, nativeMapView->getMap().getStyleURL()); +} + void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* newStyleJson) { assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); @@ -1816,6 +1822,7 @@ void registerNatives(JavaVM *vm) { MAKE_NATIVE_METHOD(nativeSetClasses, "(JLjava/util/List;)V"), MAKE_NATIVE_METHOD(nativeGetClasses, "(J)Ljava/util/List;"), MAKE_NATIVE_METHOD(nativeSetStyleUrl, "(JLjava/lang/String;)V"), + MAKE_NATIVE_METHOD(nativeGetStyleUrl, "(J)Ljava/lang/String;"), MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;)V"), MAKE_NATIVE_METHOD(nativeGetStyleJson, "(J)Ljava/lang/String;"), MAKE_NATIVE_METHOD(nativeSetAccessToken, "(JLjava/lang/String;)V"), |