[android] #4396 - UserLocationView improvements

This commit is contained in:
Larry Geromegnace
2016-02-25 14:24:17 +01:00
committed by Tobrun
parent 668405e61f
commit b3e340ca11
5 changed files with 350 additions and 99 deletions

View File

@@ -19,6 +19,7 @@ import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -880,6 +881,67 @@ public class MapView extends FrameLayout {
throw new TelemetryServiceNotConfiguredException();
}
//
// User marker location drawable management
//
/**
* Set the user location view default drawable .
*/
void setUserLocationDrawable(Drawable drawable) {
mUserLocationView.setUserLocationDrawable(drawable);
}
/**
* Set the user location view default drawable and its shadow.
*/
void setUserLocationDrawable(Drawable drawable, Drawable shadowDrawable) {
mUserLocationView.setUserLocationDrawable(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);
}
//
// Projection
//
@@ -1648,9 +1710,7 @@ public class MapView extends FrameLayout {
}
// reset tracking modes if gesture occurs
if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
resetTrackingModes();
}
resetTrackingModesIfRequired();
// Fling the map
float ease = 0.25f;
@@ -1686,10 +1746,9 @@ public class MapView extends FrameLayout {
return false;
}
if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
// reset tracking modes if gesture occurs
resetTrackingModes();
}
// reset tracking modes if gesture occurs
resetTrackingModesIfRequired();
// Cancel any animation
mNativeMapView.cancelTransitions();
@@ -1718,10 +1777,8 @@ public class MapView extends FrameLayout {
return false;
}
if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
// reset tracking modes if gesture occurs
resetTrackingModes();
}
// reset tracking modes if gesture occurs
resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY());
@@ -1803,10 +1860,8 @@ public class MapView extends FrameLayout {
return false;
}
if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
// reset tracking modes if gesture occurs
resetTrackingModes();
}
// reset tracking modes if gesture occurs
resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY());
@@ -1884,10 +1939,8 @@ public class MapView extends FrameLayout {
return false;
}
if (mMapboxMap.getTrackingSettings().isDismissTrackingOnGesture()) {
// reset tracking modes if gesture occurs
resetTrackingModes();
}
// reset tracking modes if gesture occurs
resetTrackingModesIfRequired();
mBeginTime = detector.getEventTime();
trackGestureEvent(MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY());
@@ -2367,11 +2420,28 @@ public class MapView extends FrameLayout {
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private void resetTrackingModes() {
private void resetTrackingModesIfRequired() {
TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
if (trackingSettings.isDismissLocationTrackingOnGesture()) {
resetLocationTrackingMode();
}
if (trackingSettings.isDismissBearingTrackingOnGesture()) {
resetBearingTrackingMode();
}
}
private void resetLocationTrackingMode() {
try {
TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
} catch (SecurityException ignore) {
// User did not accept location permissions
}
}
private void resetBearingTrackingMode() {
try {
setMyBearingTrackingMode(MyBearingTracking.NONE);
} catch (SecurityException ignore) {
// User did not accept location permissions
}

View File

@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.SystemClock;
import android.support.annotation.FloatRange;
@@ -576,6 +577,69 @@ public class MapboxMap {
mMapView.setAccessToken(accessToken);
}
/**
* Set the user location view default drawable .
*/
public void setUserLocationDrawable(Drawable drawable) {
mMapView.setUserLocationDrawable(drawable);
}
/**
* Set the user location view default drawable and its shadow.
*/
public void setUserLocationDrawable(Drawable drawable, Drawable shadowDrawable) {
mMapView.setUserLocationDrawable(drawable, shadowDrawable);
}
/**
* 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);
}
/**
* Returns the current Mapbox access token used to load map styles and tiles.
*

View File

@@ -14,7 +14,8 @@ public class TrackingSettings {
private MapView mapView;
private UiSettings uiSettings;
private boolean dismissTrackingOnGesture = true;
private boolean dismissLocationTrackingOnGesture = true;
private boolean dismissBearingTrackingOnGesture = true;
@MyLocationTracking.Mode
private int mMyLocationTrackingMode;
@@ -44,7 +45,7 @@ public class TrackingSettings {
public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
mMyLocationTrackingMode = myLocationTrackingMode;
mapView.setMyLocationTrackingMode(myLocationTrackingMode);
validateGesturesForTrackingModes();
validateGesturesForLocationTrackingMode();
}
/**
@@ -79,6 +80,7 @@ public class TrackingSettings {
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
mMyBearingTrackingMode = myBearingTrackingMode;
mapView.setMyBearingTrackingMode(myBearingTrackingMode);
validateGesturesForBearingTrackingMode();
}
/**
@@ -89,7 +91,7 @@ public class TrackingSettings {
* @see MyBearingTracking
*/
@UiThread
@MyLocationTracking.Mode
@MyBearingTracking.Mode
public int getMyBearingTrackingMode() {
return mMyBearingTrackingMode;
}
@@ -100,7 +102,7 @@ public class TrackingSettings {
* @return True to indicate the tracking modes will be dismissed.
*/
public boolean isDismissTrackingOnGesture() {
return dismissTrackingOnGesture;
return dismissLocationTrackingOnGesture && dismissBearingTrackingOnGesture;
}
/**
@@ -109,35 +111,67 @@ public class TrackingSettings {
* @param dismissTrackingOnGesture True to dismiss the tracking modes.
*/
public void setDismissTrackingOnGesture(boolean dismissTrackingOnGesture) {
this.dismissTrackingOnGesture = dismissTrackingOnGesture;
dismissLocationTrackingOnGesture = dismissTrackingOnGesture;
dismissBearingTrackingOnGesture = dismissTrackingOnGesture;
validateGesturesForTrackingModes();
}
private void validateGesturesForTrackingModes() {
if (!dismissTrackingOnGesture) {
int myLocationTrackingMode = getMyLocationTrackingMode();
int myBearingTrackingMode = getMyBearingTrackingMode();
validateGesturesForBearingTrackingMode();
validateGesturesForLocationTrackingMode();
}
// Enable/disable gestures based on tracking mode
private void validateGesturesForLocationTrackingMode() {
int myLocationTrackingMode = getMyLocationTrackingMode();
if (!dismissLocationTrackingOnGesture) {
if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
uiSettings.setScrollGesturesEnabled(true);
uiSettings.setRotateGesturesEnabled(true);
} else {
uiSettings.setScrollGesturesEnabled(false);
uiSettings.setRotateGesturesEnabled((myBearingTrackingMode == MyBearingTracking.NONE));
}
}else{
} else {
uiSettings.setScrollGesturesEnabled(true);
}
}
private void validateGesturesForBearingTrackingMode() {
int myBearingTrackingMode = getMyBearingTrackingMode();
if (!dismissBearingTrackingOnGesture) {
if (myBearingTrackingMode == MyBearingTracking.NONE) {
uiSettings.setRotateGesturesEnabled(true);
} else {
uiSettings.setRotateGesturesEnabled(false);
}
} else {
uiSettings.setRotateGesturesEnabled(true);
}
}
public void setDismissLocationTrackingOnGesture(boolean dismissLocationTrackingOnGesture) {
this.dismissLocationTrackingOnGesture = dismissLocationTrackingOnGesture;
validateGesturesForLocationTrackingMode();
}
public boolean isDismissLocationTrackingOnGesture() {
return dismissLocationTrackingOnGesture;
}
public void setDismissBearingTrackingOnGesture(boolean dismissBearingTrackingOnGesture) {
this.dismissBearingTrackingOnGesture = dismissBearingTrackingOnGesture;
validateGesturesForBearingTrackingMode();
}
public boolean isDismissBearingTrackingOnGesture() {
return dismissBearingTrackingOnGesture;
}
/**
* Return if location tracking is disabled
*
* @return True if location tracking is disabled.
*/
public boolean isLocationTrackingDisabled() {
public boolean isLocationTrackingDisabled(){
return mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE;
}
}

View File

@@ -19,6 +19,7 @@ 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.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
@@ -59,17 +60,12 @@ public final class UserLocationView extends View {
private Path mAccuracyPath;
private RectF mAccuracyBounds;
private Drawable mUserLocationDrawable;
private RectF mUserLocationDrawableBoundsF;
private Rect mUserLocationDrawableBounds;
private UserLocationViewDrawableHolder mHolder = new UserLocationViewDrawableHolder();
private UserLocationViewDrawableHolder mBearingHolder = new UserLocationViewDrawableHolder();
private UserLocationViewDrawableHolder mStaleHolder = new UserLocationViewDrawableHolder();
private Drawable mUserLocationBearingDrawable;
private RectF mUserLocationBearingDrawableBoundsF;
private Rect mUserLocationBearingDrawableBounds;
private Drawable mUserLocationStaleDrawable;
private RectF mUserLocationStaleDrawableBoundsF;
private Rect mUserLocationStaleDrawableBounds;
private int mShadowX = 0;
private int mShadowY = 0;
private Rect mDirtyRect;
private RectF mDirtyRectF;
@@ -137,60 +133,20 @@ public final class UserLocationView extends View {
mMarkerScreenPoint = new PointF();
mMarkerScreenMatrix = new Matrix();
mAccuracyPaintFill = new Paint();
mAccuracyPaintFill.setAntiAlias(true);
mAccuracyPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
mAccuracyPaintFill.setStyle(Paint.Style.FILL);
mAccuracyPaintFill.setColor(accuracyColor);
mAccuracyPaintFill.setAlpha((int) (255 * 0.25f));
mAccuracyPaintStroke = new Paint();
mAccuracyPaintStroke.setAntiAlias(true);
mAccuracyPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
mAccuracyPaintStroke.setStyle(Paint.Style.STROKE);
mAccuracyPaintStroke.setStrokeWidth(0.5f * density);
mAccuracyPaintStroke.setColor(accuracyColor);
mAccuracyPaintStroke.setAlpha((int) (255 * 0.5f));
setUserLocationAccuracyColor(accuracyColor);
mAccuracyPath = new Path();
mAccuracyBounds = new RectF();
mUserLocationDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location);
mUserLocationDrawableBounds = new Rect(
-mUserLocationDrawable.getIntrinsicWidth() / 2,
-mUserLocationDrawable.getIntrinsicHeight() / 2,
mUserLocationDrawable.getIntrinsicWidth() / 2,
mUserLocationDrawable.getIntrinsicHeight() / 2);
mUserLocationDrawableBoundsF = new RectF(
-mUserLocationDrawable.getIntrinsicWidth() / 2,
-mUserLocationDrawable.getIntrinsicHeight() / 2,
mUserLocationDrawable.getIntrinsicWidth() / 2,
mUserLocationDrawable.getIntrinsicHeight() / 2);
mUserLocationDrawable.setBounds(mUserLocationDrawableBounds);
mUserLocationBearingDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_bearing);
mUserLocationBearingDrawableBounds = new Rect(
-mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
-mUserLocationBearingDrawable.getIntrinsicHeight() / 2,
mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
mUserLocationBearingDrawable.getIntrinsicHeight() / 2);
mUserLocationBearingDrawableBoundsF = new RectF(
-mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
-mUserLocationBearingDrawable.getIntrinsicHeight() / 2,
mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
mUserLocationBearingDrawable.getIntrinsicHeight() / 2);
mUserLocationBearingDrawable.setBounds(mUserLocationBearingDrawableBounds);
mUserLocationStaleDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_stale);
mUserLocationStaleDrawableBounds = new Rect(
-mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
-mUserLocationStaleDrawable.getIntrinsicHeight() / 2,
mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
mUserLocationStaleDrawable.getIntrinsicHeight() / 2);
mUserLocationStaleDrawableBoundsF = new RectF(
-mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
-mUserLocationStaleDrawable.getIntrinsicHeight() / 2,
mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
mUserLocationStaleDrawable.getIntrinsicHeight() / 2);
mUserLocationStaleDrawable.setBounds(mUserLocationStaleDrawableBounds);
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) {
@@ -205,28 +161,93 @@ public final class UserLocationView extends View {
if (!mShowMarker) {
return;
}
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);
Drawable dotDrawable = mShowDirection ? mUserLocationBearingDrawable : mUserLocationDrawable;
dotDrawable = mStaleMarker ? mUserLocationStaleDrawable : dotDrawable;
// IMPORTANT also update in update()
RectF dotBounds = mShowDirection ? mUserLocationBearingDrawableBoundsF : mUserLocationDrawableBoundsF;
dotBounds = mStaleMarker ? mUserLocationStaleDrawableBoundsF : dotBounds;
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(dotBounds, Canvas.EdgeType.AA);
willDraw |= !canvas.quickReject(holder.mBounds, Canvas.EdgeType.AA);
if (willDraw) {
if (mShowAccuracy && !mStaleMarker) {
canvas.drawPath(mAccuracyPath, mAccuracyPaintFill);
canvas.drawPath(mAccuracyPath, mAccuracyPaintStroke);
}
dotDrawable.draw(canvas);
holder.mDrawable.draw(canvas);
}
canvas.restore();
}
public void setUserLocationDrawable(@NonNull Drawable drawable) {
setUserLocationDrawable(drawable, null);
}
public void setUserLocationDrawable(@NonNull Drawable drawable, @Nullable Drawable shadowDrawable) {
mHolder.setDrawable(drawable);
mHolder.setShadow(shadowDrawable);
update();
}
public void setUserLocationBearingDrawable(@NonNull Drawable drawable) {
setUserLocationBearingDrawable(drawable, null);
}
public void setUserLocationBearingDrawable(@NonNull Drawable drawable, @Nullable Drawable shadowDrawable) {
mBearingHolder.setDrawable(drawable);
mBearingHolder.setShadow(shadowDrawable);
update();
}
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) {
@@ -329,8 +350,10 @@ public final class UserLocationView extends View {
invalidate(mDirtyRect);
}
RectF dotBounds = mShowDirection ? mUserLocationBearingDrawableBoundsF : mUserLocationDrawableBoundsF;
dotBounds = mStaleMarker ? mUserLocationStaleDrawableBoundsF : dotBounds;
UserLocationViewDrawableHolder holder = getCurrentDrawableHolder();
RectF dotBounds = holder.mBounds;
RectF largerBounds = mShowAccuracy && !mStaleMarker && mAccuracyBounds.contains(dotBounds)
? mAccuracyBounds : dotBounds;
mMarkerScreenMatrix.mapRect(mDirtyRectF, largerBounds);

View File

@@ -0,0 +1,60 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* <p>Holder for the UserLocationView drawables.</p>
* <p>Holds the drawable and its shadow if set, and manage their initialization.</p>
*/
class UserLocationViewDrawableHolder {
Drawable mDrawable;
Drawable mShadow;
final RectF mBounds = new RectF();
final RectF mShadowBounds = new RectF();
public UserLocationViewDrawableHolder() {
}
public UserLocationViewDrawableHolder(Drawable drawable, Drawable shadow) {
setDrawable(drawable);
setShadow(shadow);
}
void setDrawable(@NonNull Drawable drawable) {
mDrawable = drawable;
setDrawable(mDrawable, mBounds);
}
void setShadow(@Nullable Drawable drawable) {
mShadow = drawable;
setDrawable(mShadow, mShadowBounds);
}
boolean hasShadow() {
return mShadow != null;
}
private static void setDrawable(final @Nullable Drawable drawable, final @NonNull RectF bounds) {
if (drawable != null) {
int halfWidth = drawable.getIntrinsicWidth() / 2;
int halfHeight = drawable.getIntrinsicHeight() / 2;
bounds.set(
-halfWidth,
-halfHeight,
halfWidth,
halfHeight);
drawable.setBounds(new Rect(
-halfWidth,
-halfHeight,
halfWidth,
halfHeight));
} else {
bounds.setEmpty();
}
}
}