Point list will not accept location coordinates to create linestring to draw a trailing line
Android API: Mapbox Navigation SDK version:
Steps to trigger behavior
- Get user coordinates using Location.getLatitude/getLongitude
- Add these to Point list
- Create Linestring from pointlist
Expected behavior
To intake user coordinates anytime they move and draw a trailing line behind the puck
Actual behavior
The app crashes when the coordinates are trying to be added into the Point list, if this line of code is uncommented the app runs but no line is drawn
I believe it is partly due to looking for location history and not actively calling for location updates but I dont see anywhere how to add location updates into the point list to create the linestring
See below my main activity
private MapView mapView; private static final int PERMISSION_LOCATION = 1000; public MapboxMap mapboxMap; ArrayList<Point> pointList = new ArrayList<Point>(); private PermissionsManager permissionsManager; private static final String TAG = "SimplifyLineActivity"; private List<Point> routeCoordinates; private LatLng locationHistory; public LocationManager locationManager;
@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
// Check if permissions are enabled and if not request
if (PermissionsManager.areLocationPermissionsGranted(this)) {
// Get an instance of the LocationComponent.
LocationComponent locationComponent = mapboxMap.getLocationComponent();
// Activate the LocationComponent
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
// Enable the LocationComponent so that it's actually visible on the map
locationComponent.setLocationComponentEnabled(true);
// Set the LocationComponent's camera mode
locationComponent.setCameraMode(CameraMode.TRACKING);
// Set the LocationComponent's render mode
locationComponent.setRenderMode(RenderMode.NORMAL);
} else {
permissionsManager = new PermissionsManager(this);
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
}
});
} else {
Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
finish();
}
}
@Override
public void onLocationChanged(Location location) {
location.getLongitude();
location.getLatitude();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, "pk.eyJ1IjoiYWFyb25jb252ZXJ5IiwiYSI6ImNsN2l6ZHptMTB0YnYzcHBid2hrY2Q5cXUifQ.vMh6oO3R5sWWPPxklfrHRA");
setContentView(R.layout.activity_main);
// Create supportMapFragment
SupportMapFragment mapFragment;
if (savedInstanceState == null) {
// Create fragment
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Build a Mapbox map
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
options.camera(new CameraPosition.Builder()
.target(new LatLng(38.899895, -77.03401))
.zoom(18)
.tilt(45)
.build());
// Create map fragment
mapFragment = SupportMapFragment.newInstance(options);
// Add map fragment to parent container
transaction.add(R.id.location_frag_container, mapFragment, "com.mapbox.map");
transaction.commit();
} else {
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map");
}
if (mapFragment != null) {
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
LocationComponentActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.OUTDOORS, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
List<Point> routeCoordinates = new ArrayList<>();
routeCoordinates.add(Point.fromLngLat(locationHistory.getLongitude(), locationHistory.getLatitude()));
LineString lineString = LineString.fromLngLats(routeCoordinates);
// Create the LineString from the list of coordinates and then make a GeoJSON
// FeatureCollection so we can add the line to our map as a layer.
style.addSource(new GeoJsonSource("line-source",
FeatureCollection.fromFeatures(new Feature[]{Feature.fromGeometry(lineString)
})));
// The layer properties for our line. This is where we make the line dotted, set the
// color, etc.
style.addLayer(new LineLayer("linelayer", "line-source").withProperties(
PropertyFactory.lineDasharray(new Float[]{0.01f, 2f}),
PropertyFactory.lineCap(Property.LINE_CAP_ROUND),
PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND),
PropertyFactory.lineWidth(5f),
PropertyFactory.lineColor(Color.parseColor("#e55e5e"))
));
}
});
}
});
}
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
}
}
Convert the Point collection to a collection of Feature objects, then use that to create the FeatureCollection. I suggest doing something like (verbose for clarity):
Point pointA = Point.fromLngLat(longitudeA, latitudeA);
Point pointB = Point.fromLngLat(longitudeB, latitudeB);
Feature featureA = Feature.fromGeometry(pointA);
Feature featureB = Feature.fromGeometry(pointB);
List<Feature> featureList = new ArrayList();
featureList.add(featureA);
featureList.add(featureB);
FeatureCollection fc = FeatureCollection.fromFeatures(featureList);
BTW be careful about posting your Mapbox token into a public ticket. If that's your token rather than one of the public demonstration tokens then I suggest changing it.
Hi thanks for the reply @cafesilencio
I tried implementing your suggestion and this did stop my app from crashing but it still does not produce a trailing line from the feature collection when the user moves and location therefore changes
Perhaps the issue is with how I am getting the location? But I can use the same process to produce accurate coordinates so that seems unlikely
See below my updated main activity with your suggestion
public class LocationComponentActivity extends AppCompatActivity implements OnMapReadyCallback, PermissionsListener, LocationListener, IBaseGpsListener {
public MapboxMap mapboxMap;
private PermissionsManager permissionsManager;
List<Feature> featureList = new ArrayList();
@SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent(@NonNull Style loadedMapStyle) {
// Check if permissions are enabled and if not request
if (PermissionsManager.areLocationPermissionsGranted(this)) {
// Get an instance of the LocationComponent.
LocationComponent locationComponent = mapboxMap.getLocationComponent();
// Activate the LocationComponent
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, loadedMapStyle).build());
// Enable the LocationComponent so that it's actually visible on the map
locationComponent.setLocationComponentEnabled(true);
// Set the LocationComponent's camera mode
locationComponent.setCameraMode(CameraMode.TRACKING);
// Set the LocationComponent's render mode
locationComponent.setRenderMode(RenderMode.NORMAL);
locationComponent.getLastKnownLocation();
} else {
permissionsManager = new PermissionsManager(this);
permissionsManager.requestLocationPermissions(this);
}
}
@SuppressLint("MissingPermission")
private void showLocation() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// check if gps is enabled
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
// Start locating
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 1, this);
} else {
// enable GPS
Toast.makeText(this, "Enable GPS!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
}
});
} else {
Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();
finish();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Mapbox.getInstance(this, "pk.eyJ1IjoiYWFyb25jb252ZXJ5IiwiYSI6ImNsN2l6ZHptMTB0YnYzcHBid2hrY2Q5cXUifQ.vMh6oO3R5sWWPPxklfrHRA");
setContentView(R.layout.activity_main);
// Create supportMapFragment
SupportMapFragment mapFragment;
if (savedInstanceState == null) {
// Create fragment
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Build a Mapbox map
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
options.camera(new CameraPosition.Builder()
.target(new LatLng(38.899895, -77.03401))
.zoom(18)
.tilt(45)
.build());
// Create map fragment
mapFragment = SupportMapFragment.newInstance(options);
// Add map fragment to parent container
transaction.add(R.id.location_frag_container, mapFragment, "com.mapbox.map");
transaction.commit();
} else {
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map");
}
if (mapFragment != null) {
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap ) {
LocationComponentActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.OUTDOORS, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
enableLocationComponent(style);
FeatureCollection fc = FeatureCollection.fromFeatures(featureList);
// FeatureCollection so we can add the line to our map as a layer.
style.addSource(new GeoJsonSource("line-source", fc ));
// The layer properties for our line. This is where we make the line dotted, set the
// color, etc.
style.addLayer(new LineLayer("linelayer", "line-source").withProperties(
PropertyFactory.lineDasharray(new Float[]{0.01f, 2f}),
PropertyFactory.lineCap(Property.LINE_CAP_ROUND),
PropertyFactory.lineJoin(Property.LINE_JOIN_ROUND),
PropertyFactory.lineWidth(5f),
PropertyFactory.lineColor(Color.parseColor("#e55e5e"))
));
}
});
}
});
}
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
}
@Override
public void onLocationChanged(@NonNull Location location) {
Point pointA = Point.fromLngLat(location.getLatitude(), location.getLatitude());
Point pointB = Point.fromLngLat(location.getLongitude(), location.getLongitude());
Feature featureA = Feature.fromGeometry(pointA);
Feature featureB = Feature.fromGeometry(pointB);
featureList.add(featureA);
featureList.add(featureB);
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onGpsStatusChanged(int event) {
}
}