[android] - Refactor dependencies, introduce focused components (#7189)

* [android] - refactor dependencies

* ignore tests
This commit is contained in:
Tobrun
2016-12-06 13:46:49 +01:00
committed by GitHub
parent 890b681b18
commit 9a9e7978db
38 changed files with 2666 additions and 2698 deletions

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,8 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
public interface FocalPointChangeListener {
void onFocalPointChanged(PointF pointF);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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 {
public final class MapboxMap {
private MapView mapView;
private UiSettings uiSettings;
private TrackingSettings trackingSettings;
private MyLocationViewSettings myLocationViewSettings;
private Projection projection;
private Transform transform;
private boolean myLocationEnabled;
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.OnMapClickListener onMapClickListener;
private MapboxMap.OnMapLongClickListener onMapLongClickListener;
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);
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;
}
// 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());
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,39 +1594,14 @@ 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);
}
//
// Invalidate
//
/**
* Triggers an invalidation of the map view.
*/
public void invalidate() {
mapView.invalidate();
}
/**
* Takes a snapshot of the map.
*
@@ -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);
}
//
@@ -1684,6 +1709,20 @@ public class MapboxMap {
void onFpsChanged(double fps);
}
/**
* 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.
*
@@ -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 {

View File

@@ -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
//

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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 {
public final class UiSettings {
private MapView mapView;
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);
}
}

View File

@@ -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;
}
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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);
}
}