diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index bd954c045..df20871c3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -469,11 +469,11 @@ public class MapView extends FrameLayout { outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, uiSettings.isZoomGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED_CHANGE, uiSettings.isZoomGestureChangeAllowed()); outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, uiSettings.isScrollGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE,uiSettings.isScrollGestureChangeAllowed()); + outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED_CHANGE, uiSettings.isScrollGestureChangeAllowed()); outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, uiSettings.isRotateGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE,uiSettings.isRotateGestureChangeAllowed()); + outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE, uiSettings.isRotateGestureChangeAllowed()); outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, uiSettings.isTiltGesturesEnabled()); - outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE,uiSettings.isTiltGestureChangeAllowed()); + outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE, uiSettings.isTiltGestureChangeAllowed()); outState.putBoolean(MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED, uiSettings.isZoomControlsEnabled()); // UiSettings - Compass @@ -588,6 +588,7 @@ public class MapView extends FrameLayout { if (duration != null) { actualDuration = duration; } + mUserLocationView.setTilt(pitch); mNativeMapView.setPitch(pitch, actualDuration); } @@ -889,58 +890,59 @@ public class MapView extends FrameLayout { * Set the user location view default drawable . */ void setUserLocationDrawable(Drawable drawable) { - mUserLocationView.setUserLocationDrawable(drawable); + mUserLocationView.setForegroundDrawable(drawable); } /** * Set the user location view default drawable and its shadow. */ void setUserLocationDrawable(Drawable drawable, Drawable shadowDrawable) { - mUserLocationView.setUserLocationDrawable(drawable, shadowDrawable); + mUserLocationView.setForegroundDrawable(drawable); + mUserLocationView.setShadowDrawable(shadowDrawable); } +// +// /** +// * Set the user location view bearing drawable. +// */ +// void setUserLocationBearingDrawable(Drawable drawable) { +// mUserLocationView.setUserLocationBearingDrawable(drawable); +// } +// +// /** +// * Set the user location view bearing drawable and its shadow. +// */ +// void setUserLocationBearingDrawable(Drawable drawable, Drawable shadowDrawable) { +// mUserLocationView.setUserLocationBearingDrawable(drawable, shadowDrawable); +// } +// +// /** +// * Set the stale user location view drawable. +// */ +// void setUserLocationStaleDrawable(Drawable drawable) { +// mUserLocationView.setUserLocationStaleDrawable(drawable); +// } +// +// /** +// * Set the stale user location view drawable and its shadow. +// */ +// void setUserLocationStaleDrawable(Drawable drawable, Drawable shadowDrawable) { +// mUserLocationView.setUserLocationStaleDrawable(drawable, shadowDrawable); +// } - /** - * Set the user location view bearing drawable. - */ - void setUserLocationBearingDrawable(Drawable drawable) { - mUserLocationView.setUserLocationBearingDrawable(drawable); - } - - /** - * Set the user location view bearing drawable and its shadow. - */ - void setUserLocationBearingDrawable(Drawable drawable, Drawable shadowDrawable) { - mUserLocationView.setUserLocationBearingDrawable(drawable, shadowDrawable); - } - - /** - * Set the stale user location view drawable. - */ - void setUserLocationStaleDrawable(Drawable drawable) { - mUserLocationView.setUserLocationStaleDrawable(drawable); - } - - /** - * Set the stale user location view drawable and its shadow. - */ - void setUserLocationStaleDrawable(Drawable drawable, Drawable shadowDrawable) { - mUserLocationView.setUserLocationStaleDrawable(drawable, shadowDrawable); - } - - /** - * Set the offset of the user location view shadow - */ - void setUserLocationShadowOffset(int x, int y) { - mUserLocationView.setUserLocationShadowOffset(x, y); - } - - /** - * Change the accuracy color - * @param color int real color (not a @ColorRes) - */ - void setUserLocationAccuracyColor(int color) { - mUserLocationView.setUserLocationAccuracyColor(color); - } +// /** +// * Set the offset of the user location view shadow +// */ +// void setUserLocationShadowOffset(int x, int y) { +// mUserLocationView.setUserLocationShadowOffset(x, y); +// } +// +// /** +// * Change the accuracy color +// * @param color int real color (not a @ColorRes) +// */ +// void setUserLocationAccuracyColor(int color) { +// mUserLocationView.setUserLocationAccuracyColor(color); +// } // // Projection @@ -955,7 +957,7 @@ public class MapView extends FrameLayout { } PointF toScreenLocation(@NonNull LatLng location) { - if (mDestroyed) { + if (mDestroyed || location == null) { return new PointF(); } PointF pointF = mNativeMapView.pixelForLatLng(location); @@ -1125,7 +1127,7 @@ public class MapView extends FrameLayout { } private List getMarkersInBounds(@NonNull LatLngBounds bbox) { - if (mDestroyed || bbox==null) { + if (mDestroyed || bbox == null) { return new ArrayList<>(); } @@ -1838,8 +1840,9 @@ public class MapView extends FrameLayout { mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity); } else { // around user location view - PointF centerPoint = mUserLocationView.getMarkerScreenPoint(); - mNativeMapView.scaleBy(detector.getScaleFactor(), centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity); + float x = mUserLocationView.getX() + mUserLocationView.getWidth() / 2; + float y = mUserLocationView.getY() + mUserLocationView.getHeight() / 2; + mNativeMapView.scaleBy(detector.getScaleFactor(), x / mScreenDensity, y / mScreenDensity); } } return true; @@ -1918,8 +1921,9 @@ public class MapView extends FrameLayout { detector.getFocusY() / mScreenDensity); } else { // around center userlocation - PointF centerPoint = mUserLocationView.getMarkerScreenPoint(); - mNativeMapView.setBearing(bearing, centerPoint.x / mScreenDensity, centerPoint.y / mScreenDensity); + float x = mUserLocationView.getX() + mUserLocationView.getWidth() / 2; + float y = mUserLocationView.getY() + mUserLocationView.getHeight() / 2; + mNativeMapView.setBearing(bearing, x / mScreenDensity, y / mScreenDensity); } return true; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 0162a98a9..22ff0c345 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -592,52 +592,52 @@ public class MapboxMap { } /** - * Set the user location view bearing drawable. - */ - public void setUserLocationBearingDrawable(Drawable drawable) { - mMapView.setUserLocationBearingDrawable(drawable); - } - - /** - * Set the user location view bearing drawable and its shadow. - */ - public void setUserLocationBearingDrawable(Drawable drawable, Drawable shadowDrawable) { - mMapView.setUserLocationBearingDrawable(drawable, shadowDrawable); - } - - /** - * Set the stale user location view drawable. - */ - public void setUserLocationStaleDrawable(Drawable drawable) { - mMapView.setUserLocationStaleDrawable(drawable); - } - - /** - * Set the stale user location view drawable and its shadow. - */ - public void setUserLocationStaleDrawable(Drawable drawable, Drawable shadowDrawable) { - mMapView.setUserLocationStaleDrawable(drawable, shadowDrawable); - } - - - /** - * Set the offset of the user location view shadow. - * - * @param x int x offset in pixels - * @param y int y offset in pixels - */ - public void setUserLocationShadowOffset(int x, int y) { - mMapView.setUserLocationShadowOffset(x, y); - } - - /** - * Change the accuracy circle (fill and stroke) color of the user location view - * - * @param color int real color (not a @ColorRes) - */ - public void setUserLocationAccuracyColor(int color) { - mMapView.setUserLocationAccuracyColor(color); - } +// * Set the user location view bearing drawable. +// */ +// public void setUserLocationBearingDrawable(Drawable drawable) { +// mMapView.setUserLocationBearingDrawable(drawable); +// } +// +// /** +// * Set the user location view bearing drawable and its shadow. +// */ +// public void setUserLocationBearingDrawable(Drawable drawable, Drawable shadowDrawable) { +// mMapView.setUserLocationBearingDrawable(drawable, shadowDrawable); +// } +// +// /** +// * Set the stale user location view drawable. +// */ +// public void setUserLocationStaleDrawable(Drawable drawable) { +// mMapView.setUserLocationStaleDrawable(drawable); +// } +// +// /** +// * Set the stale user location view drawable and its shadow. +// */ +// public void setUserLocationStaleDrawable(Drawable drawable, Drawable shadowDrawable) { +// mMapView.setUserLocationStaleDrawable(drawable, shadowDrawable); +// } +// +// +// /** +// * Set the offset of the user location view shadow. +// * +// * @param x int x offset in pixels +// * @param y int y offset in pixels +// */ +// public void setUserLocationShadowOffset(int x, int y) { +// mMapView.setUserLocationShadowOffset(x, y); +// } +// +// /** +// * Change the accuracy circle (fill and stroke) color of the user location view +// * +// * @param color int real color (not a @ColorRes) +// */ +// public void setUserLocationAccuracyColor(int color) { +// mMapView.setUserLocationAccuracyColor(color); +// } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java index 9c2aee5ec..208ab9886 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/UserLocationView.java @@ -3,28 +3,27 @@ package com.mapbox.mapboxsdk.maps.widgets; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; -import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Matrix; +import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Path; import android.graphics.PointF; +import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Location; -import android.os.Build; import android.os.SystemClock; -import android.support.annotation.NonNull; +import android.support.annotation.ColorInt; +import android.support.annotation.IntRange; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.View; -import android.view.ViewGroup; +import android.widget.Toast; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.camera.CameraPosition; @@ -36,6 +35,7 @@ import com.mapbox.mapboxsdk.location.LocationListener; import com.mapbox.mapboxsdk.location.LocationServices; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.Projection; +import com.mapbox.mapboxsdk.maps.UiSettings; import java.lang.ref.WeakReference; @@ -44,227 +44,390 @@ import java.lang.ref.WeakReference; */ public final class UserLocationView extends View { - private MapboxMap mMapboxMap; - private Projection mProjection; + // Foreground + private Drawable foregroundRotatedDrawable; + private Drawable foregroundDrawable; - private boolean mShowMarker; - private boolean mShowDirection; - private boolean mShowAccuracy; - private boolean mStaleMarker; - - private PointF mMarkerScreenPoint; - private Matrix mMarkerScreenMatrix; - - private Paint mAccuracyPaintFill; - private Paint mAccuracyPaintStroke; - private Path mAccuracyPath; - private RectF mAccuracyBounds; - - private UserLocationViewDrawableHolder mHolder = new UserLocationViewDrawableHolder(); - private UserLocationViewDrawableHolder mBearingHolder = new UserLocationViewDrawableHolder(); - private UserLocationViewDrawableHolder mStaleHolder = new UserLocationViewDrawableHolder(); - - private int mShadowX = 0; - private int mShadowY = 0; - - private Rect mDirtyRect; - private RectF mDirtyRectF; - - private LatLng mMarkerCoordinate; - private ValueAnimator mMarkerCoordinateAnimator; - private float mGpsMarkerDirection; - private float mCompassMarkerDirection; - private ObjectAnimator mMarkerDirectionAnimator; - private float mMarkerAccuracy; - private ObjectAnimator mMarkerAccuracyAnimator; - - private LatLng mCurrentMapViewCoordinate; + private float compassDirection; + private MyBearingListener mBearingChangeListener; private double mCurrentBearing; - private boolean mPaused = false; - private Location mUserLocation; - private UserLocationListener mUserLocationListener; - private MapboxMap.OnMyLocationChangeListener mOnMyLocationChangeListener; + private float gpsDirection; + + // Shadow + private Drawable backgroundDrawable; + + // Accuracy + private Paint accurancyPaint; + private int maxAccurancy = 50; + private float accurancy = 100; + + private double tilt; + + private Rect viewBounds; + private Rect foregroundBounds; + private Rect backgroundBounds; + + private int backgroundOffsetLeft; + private int backgroundOffsetTop; + private int backgroundOffsetRight; + private int backgroundOffsetBottom; + + private boolean paused; + private boolean showMarker; + private boolean showDirection; + private boolean showAccurancy; @MyLocationTracking.Mode - private int mMyLocationTrackingMode; + private int myLocationTrackingMode; @MyBearingTracking.Mode - private int mMyBearingTrackingMode; + private int myBearingTrackingMode; - // Compass data - private MyBearingListener mBearingChangeListener; + private MapboxMap mapboxMap; + private Projection projection; + + private LatLng markerScreenCoordinate; + private LatLng currentMapViewCoordinate; + private PointF markerScreenPoint; + + private Location location; + private UserLocationListener userLocationListener; + + private ObjectAnimator mMarkerDirectionAnimator; + private ValueAnimator mMarkerCoordinateAnimator; + private ObjectAnimator mMarkerAccuracyAnimator; + + private MapboxMap.OnMyLocationChangeListener onMyLocationChangeListener; public UserLocationView(Context context) { super(context); - initialize(context); + init(context); } public UserLocationView(Context context, AttributeSet attrs) { super(context, attrs); - initialize(context); + init(context); } public UserLocationView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - initialize(context); + init(context); } - private void initialize(Context context) { - // View configuration - setEnabled(false); - setWillNotDraw(false); + private void init(Context context) { + markerScreenCoordinate = new LatLng(); - // Layout params - ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - setLayoutParams(lp); + viewBounds = new Rect(); + +// setBackgroundColor(ContextCompat.getColor(context,android.R.color.darker_gray)); + + accurancyPaint = new Paint(); + accurancyPaint.setColor(Color.RED); + accurancyPaint.setAlpha(80); + + + setShadowDrawable(ContextCompat.getDrawable(context, R.drawable.ic_userlocationview_shadow)); + setShadowDrawableTint(Color.BLACK); + + setForegroundDrawable(ContextCompat.getDrawable(context, R.drawable.ic_userlocationview_bearing)); + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(v.getContext(), "Click: " + getMeasuredWidth() + " " + getMeasuredHeight(), Toast.LENGTH_SHORT).show(); + } + }); + + setForegroundDrawableTint(Color.RED); - // Setup sensors mBearingChangeListener = new MyBearingListener(context); - - // Setup the custom paint - Resources resources = context.getResources(); - int accuracyColor = ContextCompat.getColor(context,R.color.my_location_ring); - - float density = resources.getDisplayMetrics().density; - mMarkerCoordinate = new LatLng(0.0, 0.0); - mMarkerScreenPoint = new PointF(); - mMarkerScreenMatrix = new Matrix(); - - mAccuracyPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG); - mAccuracyPaintFill.setStyle(Paint.Style.FILL); - - mAccuracyPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); - mAccuracyPaintStroke.setStyle(Paint.Style.STROKE); - mAccuracyPaintStroke.setStrokeWidth(0.5f * density); - setUserLocationAccuracyColor(accuracyColor); - - mAccuracyPath = new Path(); - mAccuracyBounds = new RectF(); - - setUserLocationDrawable(ContextCompat.getDrawable(getContext(), R.drawable.my_location)); - setUserLocationBearingDrawable(ContextCompat.getDrawable(getContext(), R.drawable.my_location_bearing)); - setUserLocationStaleDrawable(ContextCompat.getDrawable(getContext(), R.drawable.my_location_stale)); } - public void setMapboxMap(MapboxMap mapboxMap) { - mMapboxMap = mapboxMap; - mProjection = mapboxMap.getProjection(); + public void setForegroundDrawable(Drawable drawable) { + foregroundDrawable = drawable; + //TODO remove test only +// foregroundDrawable.setAlpha(80); + invalidateBounds(); + } + + public void setForegroundDrawableTint(@ColorInt int color) { + if (foregroundDrawable == null) { + return; + } + foregroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + + public PointF getForegroundCenter() { + return new PointF(foregroundBounds.centerX(), foregroundBounds.centerY()); + } + + public void setShadowDrawable(Drawable drawable) { + setShadowDrawable(drawable, 0, 0, 0, 0); + } + + public void setShadowDrawable(Drawable drawable, int left, int top, int right, int bottom) { + backgroundDrawable = drawable; + backgroundOffsetLeft = left; + backgroundOffsetTop = top; + backgroundOffsetRight = right; + backgroundOffsetBottom = bottom; + invalidateBounds(); + } + + public void setShadowDrawableTint(@ColorInt int color) { + if (backgroundDrawable == null) { + return; + } + + backgroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + + public void setAccurancyTint(@ColorInt int color, @IntRange(from = 0, to = 100) int alpha) { + accurancyPaint.setColor(color); + accurancyPaint.setAlpha(alpha); + } + + private void invalidateBounds() { + if (backgroundDrawable == null || foregroundDrawable == null) { + return; + } + + int backgroundWidth = backgroundDrawable.getIntrinsicWidth(); + int backgroundHeight = backgroundDrawable.getIntrinsicHeight(); + + int foregroundWidth = foregroundDrawable.getIntrinsicWidth(); + int foregroundHeight = foregroundDrawable.getIntrinsicHeight(); + + int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight; + int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom; + + int accurancyWidth = 2 * maxAccurancy; + + backgroundBounds = new Rect(accurancyWidth - (backgroundWidth / 2) + horizontalOffset, accurancyWidth + verticalOffset - (backgroundWidth / 2), accurancyWidth + (backgroundWidth / 2) + horizontalOffset, accurancyWidth + (backgroundHeight / 2) + verticalOffset); + foregroundBounds = new Rect(accurancyWidth - (foregroundWidth / 2), accurancyWidth - (foregroundHeight / 2), accurancyWidth + (foregroundWidth / 2), accurancyWidth + (foregroundHeight / 2)); + + // invoke a new measure + invalidate(); } @Override - public void onDraw(Canvas canvas) { + protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (!mShowMarker) { - return; + if (foregroundBounds != null) { + canvas.drawCircle(foregroundBounds.centerX(), foregroundBounds.centerY(), foregroundBounds.width() / 2 + (accurancy / 100 * (getWidth() - foregroundBounds.width()) / 2), accurancyPaint); + } + + if (backgroundDrawable != null) { + backgroundDrawable.draw(canvas); + } + + // todo optimise + if (foregroundDrawable != null && foregroundBounds != null) { + getRotateDrawable(foregroundDrawable, compassDirection).draw(canvas); } - UserLocationViewDrawableHolder holder = getCurrentDrawableHolder(); - drawShadow(canvas, holder); - draw(canvas, holder); } - private UserLocationViewDrawableHolder getCurrentDrawableHolder() { - UserLocationViewDrawableHolder holder = mShowDirection ? mBearingHolder : mHolder; - return mStaleMarker ? mStaleHolder : holder; - } - - private void drawShadow(Canvas canvas, UserLocationViewDrawableHolder holder) { - if (!holder.hasShadow()) { - return; - } - canvas.save(); - canvas.translate(mShadowX, mShadowY); - canvas.concat(mMarkerScreenMatrix); - boolean willDraw = !canvas.quickReject(holder.mShadowBounds, Canvas.EdgeType.AA); - - if (willDraw) { - holder.mShadow.draw(canvas); - } - canvas.restore(); - } - - private void draw(Canvas canvas, UserLocationViewDrawableHolder holder) { - canvas.save(); - canvas.concat(mMarkerScreenMatrix); - boolean willDraw = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN || !canvas.isHardwareAccelerated()) { - willDraw = mShowAccuracy && !mStaleMarker && !canvas.quickReject(mAccuracyPath, Canvas.EdgeType.AA); - } - willDraw |= !canvas.quickReject(holder.mBounds, Canvas.EdgeType.AA); - - if (willDraw) { - if (mShowAccuracy && !mStaleMarker) { - canvas.drawPath(mAccuracyPath, mAccuracyPaintFill); - canvas.drawPath(mAccuracyPath, mAccuracyPaintStroke); + private Drawable getRotateDrawable(final Drawable d, final float angle) { + final Drawable[] arD = {d}; + foregroundRotatedDrawable = new LayerDrawable(arD) { + @Override + public void draw(final Canvas canvas) { + canvas.save(); + canvas.rotate(angle, foregroundBounds.centerX(), foregroundBounds.centerY()); + super.draw(canvas); + canvas.restore(); } - holder.mDrawable.draw(canvas); + }; + return foregroundRotatedDrawable; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + // position drawables within view + if (foregroundDrawable != null && foregroundBounds != null) { + foregroundDrawable.setBounds(foregroundBounds); + viewBounds.left = foregroundBounds.left; + viewBounds.top = foregroundBounds.top; + viewBounds.right = foregroundBounds.right; + viewBounds.bottom = foregroundBounds.bottom; } - canvas.restore(); + + if (backgroundDrawable != null && backgroundBounds != null) { + backgroundDrawable.setBounds(backgroundBounds); + viewBounds.union(backgroundBounds); + } + + setMeasuredDimension(4 * maxAccurancy, 4 * maxAccurancy); } - - public void setUserLocationDrawable(@NonNull Drawable drawable) { - setUserLocationDrawable(drawable, null); + //TODO add android annotation for floatrange + public void setTilt(double tilt) { + this.tilt = tilt; + setRotationX((float) tilt); } - public void setUserLocationDrawable(@NonNull Drawable drawable, @Nullable Drawable shadowDrawable) { - mHolder.setDrawable(drawable); - mHolder.setShadow(shadowDrawable); - update(); + public void setDirection(float direction) { + if (myBearingTrackingMode == MyBearingTracking.COMPASS) { + compassDirection = direction % 360.0f; + } else { + gpsDirection = direction % 360.0f; + } + updateOnNextFrame(); + } +// +// public void setMaxAccurancy(int maxAccurancy) { +// this.maxAccurancy = maxAccurancy; +// invalidateBounds(); +// } + + public void setAccurancy(float accurancy) { + this.accurancy = accurancy; + invalidate(); } - public void setUserLocationBearingDrawable(@NonNull Drawable drawable) { - setUserLocationBearingDrawable(drawable, null); + void updateOnNextFrame() { + mapboxMap.invalidate(); } - public void setUserLocationBearingDrawable(@NonNull Drawable drawable, @Nullable Drawable shadowDrawable) { - mBearingHolder.setDrawable(drawable); - mBearingHolder.setShadow(shadowDrawable); - update(); + public void onPause() { + paused = true; +// mBearingChangeListener.onPause(); +// cancelAnimations(); + toggleGps(false); } - public void setUserLocationStaleDrawable(@NonNull Drawable drawable) { - setUserLocationStaleDrawable(drawable, null); - } - - public void setUserLocationStaleDrawable(@NonNull Drawable drawable, @Nullable Drawable shadowDrawable) { - mStaleHolder.setDrawable(drawable); - mStaleHolder.setShadow(shadowDrawable); - update(); - } - - public void setUserLocationShadowOffset(int x, int y) { - mShadowX = x; - mShadowY = y; - update(); - } - - public void setUserLocationAccuracyColor(int color) { - mAccuracyPaintFill.setColor(color); - mAccuracyPaintFill.setAlpha((int) (255 * 0.25f)); - mAccuracyPaintStroke.setColor(color); - mAccuracyPaintStroke.setAlpha((int) (255 * 0.5f)); - update(); - } - - public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { - mMyLocationTrackingMode = myLocationTrackingMode; - - if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && mUserLocation != null) { - // center map directly if we have a location fix - mMarkerCoordinate = new LatLng(mUserLocation.getLatitude(), mUserLocation.getLongitude()); - mMapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(mUserLocation))); - - // center view directly - mMarkerScreenMatrix.reset(); - mMarkerScreenPoint = getMarkerScreenPoint(); - mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y); + public void onResume() { + paused = false; + if (myBearingTrackingMode == MyBearingTracking.COMPASS) { +// mBearingChangeListener.onResume(); + } + if (isEnabled()) { + toggleGps(true); } } + public boolean isPaused() { + return paused; + } + + public void update() { + if (isEnabled() && showMarker) { + setVisibility(View.VISIBLE); + +// mStaleMarker = isStale(mUserLocation); + + // compute new marker position + // TODO add JNI method that takes existing pointf + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + markerScreenPoint = getMarkerScreenPoint(); + +// markerScreenPoint = new PointF(((uiSettings.getWidth() - getWidth() + contentPadding[0] - contentPadding[2]) / 2) +// , ((uiSettings.getHeight() - getHeight() - contentPadding[3] + contentPadding[1]) / 2)); + + setX(markerScreenPoint.x-getWidth()/2); + setY(markerScreenPoint.y-getHeight()/2); + } else if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + double bearing = 0; + if (showDirection) { + bearing = myBearingTrackingMode == MyBearingTracking.COMPASS ? mBearingChangeListener.getCompassBearing() : location.getBearing(); + } else { + bearing = mapboxMap.getCameraPosition().bearing; + } + + if (currentMapViewCoordinate == null) { + currentMapViewCoordinate = mapboxMap.getCameraPosition().target; + } + + // only update if there is an actual change + if ((!currentMapViewCoordinate.equals(markerScreenCoordinate)) || (!(mCurrentBearing == bearing))) { + + CameraPosition cameraPosition = new CameraPosition.Builder() + .target(markerScreenCoordinate) + .bearing(bearing) + .build(); + mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 300, null); + +// mMarkerScreenMatrix.reset(); + markerScreenPoint = getMarkerScreenPoint(); +// mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y); + + // set values for next check for actual change + currentMapViewCoordinate = markerScreenCoordinate; + mCurrentBearing = bearing; + } + } + + // rotate so arrow in points to bearing + if (showDirection) { + if (myBearingTrackingMode == MyBearingTracking.COMPASS && myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + setDirection(compassDirection); +// mMarkerScreenMatrix.preRotate((float)(mCompassMarkerDirection + mMapboxMap.getCameraPosition().bearing)); + } else if (myBearingTrackingMode == MyBearingTracking.GPS) { + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + setDirection(gpsDirection); +// mMarkerScreenMatrix.preRotate((float)(mGpsMarkerDirection + mMapboxMap.getCameraPosition().bearing)); + } else { +// MarkerScreenMatrix.preRotate(gpsDirection); + } + } + } +// +// // adjust accuracy circle +// if (mShowAccuracy && !mStaleMarker) { +// mAccuracyPath.reset(); +// mAccuracyPath.addCircle(0.0f, 0.0f, +// (float) (mMarkerAccuracy / mMapboxMap.getProjection().getMetersPerPixelAtLatitude( +// mMarkerCoordinate.getLatitude())), +// Path.Direction.CW); +// +// mAccuracyPath.computeBounds(mAccuracyBounds, false); +// mAccuracyBounds.inset(-1.0f, -1.0f); +// } +// +// // invalidate changed pixels +// if (mDirtyRect == null) { +// mDirtyRect = new Rect(); +// mDirtyRectF = new RectF(); +// } else { +// // the old marker location +// invalidate(mDirtyRect); +// } + +// UserLocationViewDrawableHolder holder = getCurrentDrawableHolder(); +// +// +// RectF dotBounds = holder.mBounds; +// RectF largerBounds = mShowAccuracy && !mStaleMarker && mAccuracyBounds.contains(dotBounds) +// ? mAccuracyBounds : dotBounds; +// mMarkerScreenMatrix.mapRect(mDirtyRectF, largerBounds); +// mDirtyRectF.roundOut(mDirtyRect); +// invalidate(mDirtyRect); // the new marker location + } else { + setVisibility(View.INVISIBLE); + } + } + + public PointF getMarkerScreenPoint() { + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + markerScreenPoint = projection.toScreenLocation(markerScreenCoordinate); + } else { + int[] contentPadding = mapboxMap.getPadding(); + UiSettings uiSettings = mapboxMap.getUiSettings(); + markerScreenPoint = new PointF(((uiSettings.getWidth() - getWidth() + contentPadding[0] - contentPadding[2]) / 2) + , ((uiSettings.getHeight() - getHeight() - contentPadding[3] + contentPadding[1]) / 2)); + } + return markerScreenPoint; + } + + public void setMapboxMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + this.projection = mapboxMap.getProjection(); + } + + @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); @@ -272,102 +435,6 @@ public final class UserLocationView extends View { toggleGps(enabled); } - public void update() { - if (isEnabled() && mShowMarker) { - setVisibility(View.VISIBLE); - - mStaleMarker = isStale(mUserLocation); - - // compute new marker position - // TODO add JNI method that takes existing pointf - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - mMarkerScreenPoint = getMarkerScreenPoint(); - mMarkerScreenMatrix.reset(); - mMarkerScreenMatrix.setTranslate( - mMarkerScreenPoint.x, - mMarkerScreenPoint.y); - - } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - double bearing; - if (mShowDirection) { - bearing = mMyBearingTrackingMode == MyBearingTracking.COMPASS ? mBearingChangeListener.getCompassBearing() : mUserLocation.getBearing(); - } else { - bearing = mMapboxMap.getCameraPosition().bearing; - } - - if (mCurrentMapViewCoordinate == null) { - mCurrentMapViewCoordinate = mMapboxMap.getCameraPosition().target; - } - - // only update if there is an actual change - if ((!mCurrentMapViewCoordinate.equals(mMarkerCoordinate)) || (!(mCurrentBearing == bearing))) { - CameraPosition cameraPosition = new CameraPosition.Builder() - .target(mMarkerCoordinate) - .bearing(bearing) - .build(); - mMapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 300, null); - mMarkerScreenMatrix.reset(); - mMarkerScreenPoint = getMarkerScreenPoint(); - mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y); - - // set values for next check for actual change - mCurrentMapViewCoordinate = mMarkerCoordinate; - mCurrentBearing = bearing; - } - } - - // rotate so arrow in points to bearing - if (mShowDirection) { - if (mMyBearingTrackingMode == MyBearingTracking.COMPASS && mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - mMarkerScreenMatrix.preRotate((float)(mCompassMarkerDirection + mMapboxMap.getCameraPosition().bearing)); - } else if (mMyBearingTrackingMode == MyBearingTracking.GPS) { - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - mMarkerScreenMatrix.preRotate((float)(mGpsMarkerDirection + mMapboxMap.getCameraPosition().bearing)); - } else { - mMarkerScreenMatrix.preRotate(mGpsMarkerDirection); - } - } - } - - // adjust accuracy circle - if (mShowAccuracy && !mStaleMarker) { - mAccuracyPath.reset(); - mAccuracyPath.addCircle(0.0f, 0.0f, - (float) (mMarkerAccuracy / mMapboxMap.getProjection().getMetersPerPixelAtLatitude( - mMarkerCoordinate.getLatitude())), - Path.Direction.CW); - - mAccuracyPath.computeBounds(mAccuracyBounds, false); - mAccuracyBounds.inset(-1.0f, -1.0f); - } - - // invalidate changed pixels - if (mDirtyRect == null) { - mDirtyRect = new Rect(); - mDirtyRectF = new RectF(); - } else { - // the old marker location - invalidate(mDirtyRect); - } - - UserLocationViewDrawableHolder holder = getCurrentDrawableHolder(); - - - RectF dotBounds = holder.mBounds; - RectF largerBounds = mShowAccuracy && !mStaleMarker && mAccuracyBounds.contains(dotBounds) - ? mAccuracyBounds : dotBounds; - mMarkerScreenMatrix.mapRect(mDirtyRectF, largerBounds); - mDirtyRectF.roundOut(mDirtyRect); - invalidate(mDirtyRect); // the new marker location - } else { - setVisibility(View.INVISIBLE); - } - } - - public Location getLocation() { - return mUserLocation; - } - /** * Enabled / Disable GPS location updates along with updating the UI * @@ -381,42 +448,219 @@ public final class UserLocationView extends View { // Set an initial location if one available Location lastLocation = locationServices.getLastLocation(); if (lastLocation != null) { - setLocation(lastLocation); + location = lastLocation; } - if (mUserLocationListener == null) { - mUserLocationListener = new UserLocationListener(this); + if (userLocationListener == null) { + userLocationListener = new UserLocationListener(this); } // Register for Location Updates - locationServices.addLocationListener(mUserLocationListener); + locationServices.addLocationListener(userLocationListener); } else { // Disable location and user dot - setLocation(null); + location = null; // Deregister for Location Updates - locationServices.removeLocationListener(mUserLocationListener); + locationServices.removeLocationListener(userLocationListener); } locationServices.toggleGPS(enableGps); } - public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { - mMyBearingTrackingMode = myBearingTrackingMode; + public Location getLocation() { + return location; + } - if (myBearingTrackingMode == MyBearingTracking.COMPASS) { - mShowAccuracy = false; - mShowDirection = true; - mBearingChangeListener.onResume(); + public void cancelAnimations() { + if (mMarkerCoordinateAnimator != null) { + mMarkerCoordinateAnimator.cancel(); + mMarkerCoordinateAnimator = null; + } + + if (mMarkerDirectionAnimator != null) { + mMarkerDirectionAnimator.cancel(); + mMarkerDirectionAnimator = null; + } + +// if (mMarkerAccuracyAnimator != null) { +// mMarkerAccuracyAnimator.cancel(); +// mMarkerAccuracyAnimator = null; +// } + } + + public void setLocation(Location location) { + // if null we should hide the marker + if (location == null) { + showMarker = false; + showDirection = false; + showAccurancy = false; + + cancelAnimations(); + + location = null; + return; + } + + cancelAnimations(); + showMarker = true; + + LatLng previousCoordinate; + if (this.location == null) { + previousCoordinate = new LatLng(location); } else { - mBearingChangeListener.onPause(); - if (myBearingTrackingMode == MyBearingTracking.GPS) { - mShowDirection = (mUserLocation != null) && mUserLocation.hasBearing(); - } else { - mShowDirection = false; + previousCoordinate = new LatLng(this.location); + } + + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + // moving marker above map + mMarkerCoordinateAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); + mMarkerCoordinateAnimator.setDuration(1000); + mMarkerCoordinateAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener( + previousCoordinate, new LatLng(location) + )); + mMarkerCoordinateAnimator.start(); + markerScreenCoordinate = new LatLng(location); + } else { + // moving map under the tracker + markerScreenCoordinate = new LatLng(location); + } + + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE && myBearingTrackingMode == MyBearingTracking.GPS) { + // show GPS direction + showDirection = location.hasBearing(); + if (showDirection) { + if (this.location != null && this.location.hasBearing()) { + gpsDirection = this.location.getBearing(); + } + float oldDir = gpsDirection; + float newDir = location.getBearing(); + float diff = oldDir - newDir; + if (diff > 180.0f) { + newDir += 360.0f; + } else if (diff < -180.0f) { + newDir -= 360.f; + } + mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir); + mMarkerDirectionAnimator.setDuration(1000); + mMarkerDirectionAnimator.start(); + } + } else if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW && myBearingTrackingMode == MyBearingTracking.GPS) { + // always show north & rotate map below + showDirection = true; + gpsDirection = 0; + } + + showAccurancy = location.hasAccuracy(); + if (showAccurancy) { + if (this.location != null && this.location.hasAccuracy()) { + accurancy = this.location.getAccuracy(); + } + mMarkerAccuracyAnimator = ObjectAnimator.ofFloat(this, "accuracy", location.getAccuracy()); + mMarkerAccuracyAnimator.setDuration(1000); + mMarkerAccuracyAnimator.start(); + } + + this.location = location; + updateOnNextFrame(); + + if (onMyLocationChangeListener != null) { + onMyLocationChangeListener.onMyLocationChange(location); + } + } + + public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { +// mOnMyLocationChangeListener = listener; + } + + + public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) { + this.myBearingTrackingMode = myBearingTrackingMode; + +// if (myBearingTrackingMode == MyBearingTracking.COMPASS) { +// mShowAccuracy = false; +// mShowDirection = true; +// mBearingChangeListener.onResume(); +// } else { +// mBearingChangeListener.onPause(); +// if (myBearingTrackingMode == MyBearingTracking.GPS) { +// mShowDirection = (mUserLocation != null) && mUserLocation.hasBearing(); +// } else { +// mShowDirection = false; +// } +// } + update(); + } + + public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) { + this.myLocationTrackingMode = myLocationTrackingMode; + + if (myLocationTrackingMode != MyLocationTracking.TRACKING_NONE && location != null) { + // center map directly if we have a location fix + markerScreenCoordinate = new LatLng(location.getLatitude(), location.getLongitude()); + mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(location))); + + // center view directly +// mMarkerScreenMatrix.reset(); + markerScreenPoint = getMarkerScreenPoint(); + setX(markerScreenPoint.x); + setY(markerScreenPoint.y); +// mMarkerScreenMatrix.setTranslate(mMarkerScreenPoint.x, mMarkerScreenPoint.y); + } + } + + private void setCompass(float bearing) { + if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { + // animate marker + showDirection = true; + float oldDir = compassDirection; + float newDir = bearing; + float diff = oldDir - newDir; + if (diff > 180.0f) { + newDir += 360.0f; + } else if (diff < -180.0f) { + newDir -= 360.f; + } + mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir); + mMarkerDirectionAnimator.setDuration(1000); + mMarkerDirectionAnimator.start(); + compassDirection = bearing; + + } else if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + cancelAnimations(); + if (myBearingTrackingMode == MyBearingTracking.COMPASS) { + // always show north & change map direction + showDirection = true; + gpsDirection = 0; + compassDirection = 0; + update(); + } + } else { + showDirection = false; + } + } + + private static class UserLocationListener implements LocationListener { + + private WeakReference mUserLocationView; + + public UserLocationListener(UserLocationView userLocationView) { + mUserLocationView = new WeakReference<>(userLocationView); + } + + + /** + * Callback method for receiving location updates from LocationServices. + * + * @param location The new Location data + */ + @Override + public void onLocationChanged(Location location) { + UserLocationView locationView = mUserLocationView.get(); + if (locationView != null && !locationView.isPaused()) { + locationView.setLocation(location); } } - update(); } private class MyBearingListener implements SensorEventListener { @@ -461,7 +705,7 @@ public final class UserLocationView extends View { @Override public void onSensorChanged(SensorEvent event) { - if (mPaused) { + if (paused) { return; } @@ -503,224 +747,6 @@ public final class UserLocationView extends View { } } - private static class UserLocationListener implements LocationListener { - - private WeakReference mUserLocationView; - - public UserLocationListener(UserLocationView userLocationView) { - mUserLocationView = new WeakReference<>(userLocationView); - } - - - /** - * Callback method for receiving location updates from LocationServices. - * - * @param location The new Location data - */ - @Override - public void onLocationChanged(Location location) { - UserLocationView locationView = mUserLocationView.get(); - if (locationView != null && !locationView.isPaused()) { - locationView.setLocation(location); - } - } - } - - private boolean isStale(Location location) { - if (location != null && mMyBearingTrackingMode != MyBearingTracking.COMPASS) { - long ageInNanos; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - ageInNanos = SystemClock.elapsedRealtimeNanos() - - location.getElapsedRealtimeNanos(); - } else { - ageInNanos = (System.currentTimeMillis() - location.getTime()) * 1000 * 1000; - } - final long oneMinuteInNanos = 60L * 1000 * 1000 * 1000; - return ageInNanos > oneMinuteInNanos; - } else { - return false; - } - } - - // Handles location updates from GPS - private void setLocation(Location location) { - // if null we should hide the marker - if (location == null) { - mShowMarker = false; - mShowDirection = false; - mShowAccuracy = false; - - cancelAnimations(); - - mUserLocation = null; - return; - } - - if (mMarkerCoordinateAnimator != null) { - mMarkerCoordinateAnimator.end(); - mMarkerCoordinateAnimator = null; - } - - if (mMarkerDirectionAnimator != null) { - mMarkerDirectionAnimator.end(); - mMarkerDirectionAnimator = null; - } - - if (mMarkerAccuracyAnimator != null) { - mMarkerAccuracyAnimator.end(); - mMarkerAccuracyAnimator = null; - } - - mShowMarker = true; - - LatLng previousCoordinate; - if (mUserLocation == null) { - previousCoordinate = new LatLng(location); - } else { - previousCoordinate = new LatLng(mUserLocation); - } - - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - // moving marker above map - mMarkerCoordinateAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - mMarkerCoordinateAnimator.setDuration(1000); - mMarkerCoordinateAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener( - previousCoordinate, new LatLng(location) - )); - mMarkerCoordinateAnimator.start(); - mMarkerCoordinate = new LatLng(location); - } else { - // moving map under the tracker - mMarkerCoordinate = new LatLng(location); - } - - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE && mMyBearingTrackingMode == MyBearingTracking.GPS) { - // show GPS direction - mShowDirection = location.hasBearing(); - if (mShowDirection) { - if (mUserLocation != null && mUserLocation.hasBearing()) { - mGpsMarkerDirection = mUserLocation.getBearing(); - } - float oldDir = mGpsMarkerDirection; - float newDir = location.getBearing(); - float diff = oldDir - newDir; - if (diff > 180.0f) { - newDir += 360.0f; - } else if (diff < -180.0f) { - newDir -= 360.f; - } - mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir); - mMarkerDirectionAnimator.setDuration(1000); - mMarkerDirectionAnimator.start(); - } - } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW && mMyBearingTrackingMode == MyBearingTracking.GPS) { - // always show north & rotate map below - mShowDirection = true; - mGpsMarkerDirection = 0; - } - - mShowAccuracy = location.hasAccuracy(); - if (mShowAccuracy) { - if (mUserLocation != null && mUserLocation.hasAccuracy()) { - mMarkerAccuracy = mUserLocation.getAccuracy(); - } - mMarkerAccuracyAnimator = ObjectAnimator.ofFloat(this, "accuracy", location.getAccuracy()); - mMarkerAccuracyAnimator.setDuration(1000); - mMarkerAccuracyAnimator.start(); - } - - mUserLocation = location; - updateOnNextFrame(); - - if (mOnMyLocationChangeListener != null) { - mOnMyLocationChangeListener.onMyLocationChange(location); - } - } - - // handles compass sensor updates - private void setCompass(float bearing) { - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - // animate marker - mShowDirection = true; - float oldDir = mCompassMarkerDirection; - float newDir = bearing; - float diff = oldDir - newDir; - if (diff > 180.0f) { - newDir += 360.0f; - } else if (diff < -180.0f) { - newDir -= 360.f; - } - mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir); - mMarkerDirectionAnimator.setDuration(1000); - mMarkerDirectionAnimator.start(); - mCompassMarkerDirection = bearing; - - } else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { - cancelAnimations(); - if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) { - // always show north & change map direction - mShowDirection = true; - mGpsMarkerDirection = 0; - mCompassMarkerDirection = 0; - update(); - } - } - } - - void updateOnNextFrame() { - mMapboxMap.invalidate(); - } - - public void onPause() { - mPaused = true; - mBearingChangeListener.onPause(); - cancelAnimations(); - toggleGps(false); - } - - public void onResume() { - mPaused = false; - if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) { - mBearingChangeListener.onResume(); - } - if (isEnabled()) { - toggleGps(true); - } - } - - public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { - mOnMyLocationChangeListener = listener; - } - - // public for animator only - public float getDirection() { - if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) { - return mCompassMarkerDirection; - } - return mGpsMarkerDirection; - } - - // public for animator only - public void setDirection(float direction) { - if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) { - mCompassMarkerDirection = direction % 360.0f; - } else { - mGpsMarkerDirection = direction % 360.0f; - } - updateOnNextFrame(); - } - - // public for animator only - public float getAccuracy() { - return mMarkerAccuracy; - } - - // public for animator only - public void setAccuracy(float accuracy) { - mMarkerAccuracy = accuracy; - updateOnNextFrame(); - } - private class MarkerCoordinateAnimatorListener implements ValueAnimator.AnimatorUpdateListener { private double mFromLat; @@ -740,41 +766,11 @@ public final class UserLocationView extends View { float frac = animation.getAnimatedFraction(); double latitude = mFromLat + (mToLat - mFromLat) * frac; double longitude = mFromLng + (mToLng - mFromLng) * frac; - mMarkerCoordinate.setLatitude(latitude); - mMarkerCoordinate.setLongitude(longitude); + markerScreenCoordinate.setLatitude(latitude); + markerScreenCoordinate.setLongitude(longitude); updateOnNextFrame(); } } - public void cancelAnimations() { - if (mMarkerCoordinateAnimator != null) { - mMarkerCoordinateAnimator.cancel(); - mMarkerCoordinateAnimator = null; - } - if (mMarkerDirectionAnimator != null) { - mMarkerDirectionAnimator.cancel(); - mMarkerDirectionAnimator = null; - } - - if (mMarkerAccuracyAnimator != null) { - mMarkerAccuracyAnimator.cancel(); - mMarkerAccuracyAnimator = null; - } - } - - public boolean isPaused() { - return mPaused; - } - - public PointF getMarkerScreenPoint() { - if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) { - mMarkerScreenPoint = mProjection.toScreenLocation(mMarkerCoordinate); - } else { - int[] contentPadding = mMapboxMap.getPadding(); - mMarkerScreenPoint = new PointF(((getMeasuredWidth() + contentPadding[0] - contentPadding[2]) / 2) - , ((getMeasuredHeight() - contentPadding[3] + contentPadding[1]) / 2)); - } - return mMarkerScreenPoint; - } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_bearing.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_bearing.png new file mode 100644 index 000000000..e5ff0808e Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_bearing.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_normal.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_normal.png new file mode 100644 index 000000000..74d035d1a Binary files /dev/null and b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_userlocationview_normal.png differ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_userlocationview_shadow.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_userlocationview_shadow.xml new file mode 100644 index 000000000..20000c2fe --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_userlocationview_shadow.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml index 5167ecf93..0793acbba 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml @@ -9,4 +9,6 @@ 10dp 16dp 76dp + 19dp + 20dp