[android] #2797 - addLocationBearing part one

This commit is contained in:
Tobrun
2015-10-27 12:28:19 +01:00
parent a2ac435171
commit 8fdc033eab
8 changed files with 366 additions and 77 deletions

View File

@@ -0,0 +1,29 @@
package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* MyBearingTracking exposes different types bearing tracking modes.
*
* @see
* @see
*/
public class MyBearingTracking {
/**
* Indicates the parameter accepts one of the values from {@link MyBearingTracking}.
*/
@IntDef({NONE, COMPASS, GPS, /**COMBINED**/})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
public static final int NONE = 0x00000000;
public static final int COMPASS = 0x00000004;
public static final int GPS = 0x00000008;
// public static final int COMBINED = 0x00000012;
}

View File

@@ -8,7 +8,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* MyLocationTracking exposes different types of location tracking modes.
* MyLocationTracking exposes different types of locational tracking modes.
*
* @see MapView#setMyLocationTrackingMode(int)
* @see com.mapbox.mapboxsdk.views.UserLocationView#setMyLocationTrackingMode(int)
@@ -18,7 +18,7 @@ public class MyLocationTracking {
/**
* Indicates the parameter accepts one of the values from {@link MyLocationTracking}.
*/
@IntDef({TRACKING_NONE, TRACKING_FOLLOW, /**TRACKING_FOLLOW_BEARING_GPS, TRACKING_FOLLOW_BEARING_COMPASS, TRACKING_FOLLOW_BEARING**/})
@IntDef({TRACKING_NONE, TRACKING_FOLLOW})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
@@ -29,25 +29,8 @@ public class MyLocationTracking {
public static final int TRACKING_NONE = 0x00000000;
/**
* Tracking the only the location of the user.
* Tracking user, {@link MapView} will reposition to center of {@link com.mapbox.mapboxsdk.views.UserLocationView}
*/
public static final int TRACKING_FOLLOW = 0x00000004;
// /**
// * Tracking the location of the user with bearing from GPS.
// */
// public static final int TRACKING_FOLLOW_BEARING_GPS = 0x00000008;
//
// /**
// * Tracking the location of the user with bearing from compass.
// */
// public static final int TRACKING_FOLLOW_BEARING_COMPASS = 0x00000012;
//
// /**
// * Tracking the location fot the user with bearing from GPS or compass.
// * <p>
// * The best source of bearing is selected automatically.
// */
// public static final int TRACKING_FOLLOW_BEARING = 0x00000016;
}

View File

@@ -64,6 +64,7 @@ import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.annotations.Sprite;
import com.mapbox.mapboxsdk.annotations.SpriteFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
@@ -889,6 +890,7 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public void onStart() {
mUserLocationView.onStart();
}
/**
@@ -896,7 +898,7 @@ public final class MapView extends FrameLayout {
*/
@UiThread
public void onStop() {
mUserLocationView.cancelAnimations();
mUserLocationView.onStop();
}
/**
@@ -2182,7 +2184,14 @@ public final class MapView extends FrameLayout {
// Used by UserLocationView
void update() {
mNativeMapView.update();
if (mNativeMapView != null) {
mNativeMapView.update();
}
}
// Used by UserLocationView
void setBearing(float bearing) {
mNativeMapView.setBearing(bearing, 100);
}
//
@@ -3151,14 +3160,13 @@ public final class MapView extends FrameLayout {
}
/**
* Sets the current my location tracking mode.
* Set the current my location tracking mode.
* Tracking my location disables gestures and pans the viewport
* <p/>
* My location racking disables gestures, automatically moves the viewport to the users
* location and shows the direction the user is heading.
* See {@link MyLocationTracking} for different values.
*
* @param myLocationTrackingMode The my location tracking mode to use.
* Accepts one of the values from {@link MyLocationTracking.Mode}.
* @see MyLocationTracking.Mode
* @param myLocationTrackingMode The location tracking mode to be used.
* @see MyLocationTracking
*/
@UiThread
public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
@@ -3187,6 +3195,33 @@ public final class MapView extends FrameLayout {
return mUserLocationView.getMyLocationTrackingMode();
}
/**
* Set the current my bearing tracking mode.
* Tracking my bearing disables gestures and shows the direction the user is heading.
* See {@link MyBearingTracking} for different values.
*
* @param myBearingTrackingMode The bearing tracking mode to be used.
* @see MyBearingTracking
*/
@UiThread
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
mUserLocationView.setMyBearingTrackingMode(myBearingTrackingMode);
}
/**
* Returns the current user bearing tracking mode.
* See {@link MyBearingTracking} for possible return values.
*
* @return the current user bearing tracking mode.
* @see MyBearingTracking
*/
@UiThread
@MyLocationTracking.Mode
public int getMyBearingTrackingMode() {
//noinspection ResourceType
return mUserLocationView.getMyBearingTrackingMode();
}
//
// Compass
//

View File

@@ -12,16 +12,24 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.hardware.GeomagneticField;
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.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapzen.android.lost.api.LocationListener;
@@ -29,6 +37,8 @@ import com.mapzen.android.lost.api.LocationRequest;
import com.mapzen.android.lost.api.LocationServices;
import com.mapzen.android.lost.api.LostApiClient;
import java.util.ArrayDeque;
final class UserLocationView extends View {
private MapView mMapView;
@@ -83,6 +93,12 @@ final class UserLocationView extends View {
@MyLocationTracking.Mode
private int mMyLocationTrackingMode;
@MyBearingTracking.Mode
private int mMyBearingTrackingMode;
// Compass data
private MyBearingListener mBearingChangeListener;
public UserLocationView(Context context) {
super(context);
initialize(context);
@@ -116,6 +132,9 @@ final class UserLocationView extends View {
.setSmallestDisplacement(3.0f)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Setup sensors
mBearingChangeListener = new MyBearingListener(context);
// Setup the custom paint
Resources resources = context.getResources();
mDensity = resources.getDisplayMetrics().density;
@@ -183,6 +202,17 @@ final class UserLocationView extends View {
mMapView = mapView;
}
public void onStart() {
if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
mBearingChangeListener.onStart(getContext());
}
}
public void onStop() {
mBearingChangeListener.onStop();
cancelAnimations();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -321,6 +351,136 @@ final class UserLocationView extends View {
}
}
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
mMyBearingTrackingMode = myBearingTrackingMode;
if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
mBearingChangeListener.onStart(getContext());
} else {
mBearingChangeListener.onStop();
}
}
@MyBearingTracking.Mode
public int getMyBearingTrackingMode() {
return mMyBearingTrackingMode;
}
private class MyBearingListener implements SensorEventListener {
// Sensor model
private SensorManager mSensorManager;
private Sensor mSensorRotationVector;
private int mRotationDevice;
// Sensor data sensor rotation vector
private float[] mRotationMatrix = new float[16];
private float[] mRemappedMatrix = new float[16];
private float[] mOrientation = new float[3];
// Location data
private GeomagneticField mGeomagneticField;
// Controls the sensor update rate in milliseconds
private static final int UPDATE_RATE_MS = 500;
private AngleLowPassFilter mLowPassFilter;
// Compass data
private float mCompassBearing;
private long mCompassUpdateNextTimestamp = 0;
public MyBearingListener(Context context) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mSensorRotationVector = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
mLowPassFilter = new AngleLowPassFilter();
}
public void onStart(Context context) {
mRotationDevice = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
mSensorManager.registerListener(this, mSensorRotationVector, UPDATE_RATE_MS * 1000);
}
public void onStop() {
mSensorManager.unregisterListener(this, mSensorRotationVector);
}
public float getCompassBearing() {
return mCompassBearing;
}
@Override
public void onSensorChanged(SensorEvent event) {
if (mPaused) {
return;
}
switch (event.sensor.getType()) {
case Sensor.TYPE_ROTATION_VECTOR:
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
break;
}
switch (mRotationDevice) {
case Surface.ROTATION_0:
// Portrait
SensorManager.getOrientation(mRotationMatrix, mOrientation);
break;
default:
// Landscape
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_MINUS_X, mRemappedMatrix);
SensorManager.getOrientation(mRemappedMatrix, mOrientation);
break;
}
mLowPassFilter.add(mOrientation[0]);
long currentTime = System.currentTimeMillis();
if (currentTime < mCompassUpdateNextTimestamp) {
return;
}
mCompassUpdateNextTimestamp = currentTime + UPDATE_RATE_MS;
mGeomagneticField = new GeomagneticField(
(float) mUserLocation.getLatitude(),
(float) mUserLocation.getLongitude(),
(float) mUserLocation.getAltitude(),
currentTime);
mCompassBearing = (float) Math.toDegrees(mLowPassFilter.average()) + mGeomagneticField.getDeclination();
setCompass(mCompassBearing);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO add accuracy to the equiation
}
private class AngleLowPassFilter {
private final int LENGTH = 5;
private float sumSin, sumCos;
private ArrayDeque<Float> queue = new ArrayDeque<>();
public void add(float radians) {
sumSin += (float) Math.sin(radians);
sumCos += (float) Math.cos(radians);
queue.add(radians);
if (queue.size() > LENGTH) {
float old = queue.poll();
sumSin -= Math.sin(old);
sumCos -= Math.cos(old);
}
}
public float average() {
int size = queue.size();
return (float) Math.atan2(sumSin / size, sumCos / size);
}
}
}
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
@@ -399,22 +559,30 @@ final class UserLocationView extends View {
mMapView.setCenterCoordinate(mMarkerCoordinate, true);
}
mShowDirection = location.hasBearing();
if (mShowDirection) {
if (mUserLocation != null && mUserLocation.hasBearing()) {
mMarkerDirection = mUserLocation.getBearing();
if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE && mMyBearingTrackingMode == MyBearingTracking.GPS) {
// show GPS direction
mShowDirection = location.hasBearing();
if (mShowDirection) {
if (mUserLocation != null && mUserLocation.hasBearing()) {
mMarkerDirection = mUserLocation.getBearing();
}
float oldDir = mMarkerDirection;
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();
}
float oldDir = mMarkerDirection;
float newDir = location.getBearing();
float diff = oldDir - newDir;
if (diff > 180.0f) {
newDir += 360.0f;
} else if (diff < -180.0f) {
newDir -= 360.f;
} else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW && mMyBearingTrackingMode == MyBearingTracking.GPS) {
// set bearing on map
if (location.hasBearing()) {
mMapView.setBearing(mUserLocation.getBearing());
}
mMarkerDirectionAnimator = ObjectAnimator.ofFloat(this, "direction", oldDir, newDir);
mMarkerDirectionAnimator.setDuration(1000);
mMarkerDirectionAnimator.start();
}
mShowAccuracy = location.hasAccuracy();
@@ -435,6 +603,32 @@ final class UserLocationView extends View {
}
}
// handles compass sensor updates
private void setCompass(float bearing) {
if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
// animate marker
mShowDirection = true;
float oldDir = mMarkerDirection;
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();
mMarkerDirection = bearing;
} else if (mMyLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
// change map direction
if (mMyBearingTrackingMode == MyBearingTracking.COMPASS) {
mMarkerDirection = bearing;
mMapView.setBearing(mMarkerDirection);
}
}
}
void updateOnNextFrame() {
mMapView.update();
}
@@ -518,4 +712,5 @@ final class UserLocationView extends View {
mMarkerAccuracyAnimator = null;
}
}
}

View File

@@ -23,22 +23,27 @@ import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.crashlytics.android.Crashlytics;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.annotations.Sprite;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
import com.mapbox.mapboxsdk.utils.ApiAccess;
import com.mapbox.mapboxsdk.views.MapView;
import io.fabric.sdk.android.Fabric;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import io.fabric.sdk.android.Fabric;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@@ -428,6 +433,8 @@ public class MainActivity extends AppCompatActivity {
}
});
mMapView.setMyLocationEnabled(true);
mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
mMapView.setMyBearingTrackingMode(MyBearingTracking.GPS);
mLocationFAB.setColorFilter(ContextCompat.getColor(this, R.color.primary));
}
@@ -467,7 +474,7 @@ public class MainActivity extends AppCompatActivity {
List<Marker> markers = mMapView.addMarkers(markerOptionsList);
}
private MarkerOptions generateMarker(String title, String snippet, Sprite icon, double lat, double lng){
private MarkerOptions generateMarker(String title, String snippet, Sprite icon, double lat, double lng) {
return new MarkerOptions()
.position(new LatLng(lat, lng))
.title(title)

View File

@@ -13,6 +13,7 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.ApiAccess;
@@ -21,7 +22,7 @@ import com.mapbox.mapboxsdk.views.MapView;
public class MyLocationTrackingModeActivity extends AppCompatActivity implements MapView.OnMyLocationChangeListener, AdapterView.OnItemSelectedListener {
private MapView mMapView;
private Spinner mSpinner;
private Spinner mLocationSpinner, mBearingSpinner;
private Location mLocation;
@Override
@@ -39,12 +40,19 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
actionBar.setDisplayShowHomeEnabled(true);
}
ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinner = (Spinner) findViewById(R.id.spinner);
mSpinner.setAdapter(spinnerAdapter);
mSpinner.setOnItemSelectedListener(this);
mSpinner.setEnabled(false);
ArrayAdapter<CharSequence> locationTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_tracking_mode, android.R.layout.simple_spinner_item);
locationTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mLocationSpinner = (Spinner) findViewById(R.id.spinner_location);
mLocationSpinner.setAdapter(locationTrackingAdapter);
mLocationSpinner.setOnItemSelectedListener(this);
// mLocationSpinner.setEnabled(false);
ArrayAdapter<CharSequence> bearingTrackingAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.user_bearing_mode, android.R.layout.simple_spinner_item);
bearingTrackingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mBearingSpinner = (Spinner) findViewById(R.id.spinner_bearing);
mBearingSpinner.setAdapter(bearingTrackingAdapter);
mBearingSpinner.setOnItemSelectedListener(this);
// mBearingSpinner.setEnabled(false);
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.setAccessToken(ApiAccess.getToken(this));
@@ -59,7 +67,8 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
if (mLocation == null) {
// initial location to reposition map
mMapView.setCenterCoordinate(new LatLng(location.getLatitude(), location.getLongitude()));
mSpinner.setEnabled(true);
mLocationSpinner.setEnabled(true);
mBearingSpinner.setEnabled(true);
}
mLocation = location;
showSnackBar();
@@ -85,26 +94,34 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
break;
if (parent.getId() == R.id.spinner_location) {
switch (position) {
case 0:
mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
break;
case 1:
mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
break;
case 1:
mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
break;
}
} else if (parent.getId() == R.id.spinner_bearing) {
switch (position) {
case 0:
mMapView.setMyBearingTrackingMode(MyBearingTracking.NONE);
break;
// case 2:
// mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW_BEARING_GPS);
// break;
//
// case 3:
// mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW_BEARING_COMPASS);
// break;
//
// case 4:
// mMapView.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW_BEARING);
// break;
case 1:
mMapView.setMyBearingTrackingMode(MyBearingTracking.GPS);
break;
case 2:
mMapView.setMyBearingTrackingMode(MyBearingTracking.COMPASS);
break;
// case 3:
// mMapView.setMyBearingTrackingMode(MyBearingTracking.COMBINED);
// break;
}
}
}

View File

@@ -12,10 +12,29 @@
android:background="@color/primary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2">
<Spinner
android:id="@+id/spinner_location"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<Spinner
android:id="@+id/spinner_bearing"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1" />
</LinearLayout>
</android.support.v7.widget.Toolbar>

View File

@@ -54,9 +54,13 @@
<string-array name="user_tracking_mode">
<item>Disable tracking</item>
<item>Follow tracking mode</item>
<!--<item>Bearing tracking GPS mode</item>-->
<!--<item>Bearing tracking Compass mode</item>-->
<!--<item>Bearing tracking mode</item>-->
</string-array>
<string-array name="user_bearing_mode">
<item>Disable bearing</item>
<item>GPS mode</item>
<item>Compass mode</item>
<!--<item>Combined mode</item>-->
</string-array>
</resources>