diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java index f5d637df743..f10c5cb820d 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/MockNavigationActivity.java @@ -16,6 +16,8 @@ import android.widget.Toast; import com.mapbox.android.core.location.LocationEngine; +import com.mapbox.android.core.location.LocationEngineCallback; +import com.mapbox.android.core.location.LocationEngineResult; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.geojson.Point; @@ -28,6 +30,7 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.testapp.Utils; import com.mapbox.services.android.navigation.testapp.activity.notification.CustomNavigationNotification; @@ -170,25 +173,24 @@ private void newOrigin() { @SuppressLint("MissingPermission") @Override - public void onMapReady(MapboxMap mapboxMap) { + public void onMapReady(@NonNull MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - - LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this); - locationComponent.setRenderMode(RenderMode.GPS); - locationComponent.setLocationComponentEnabled(false); - navigationMapRoute = new NavigationMapRoute(navigation, mapView, mapboxMap); - - mapboxMap.addOnMapClickListener(this); - Snackbar.make(findViewById(R.id.container), "Tap map to place waypoint", BaseTransientBottomBar.LENGTH_LONG).show(); - - locationEngine = new ReplayRouteLocationEngine(); - - newOrigin(); + this.mapboxMap.addOnMapClickListener(this); + mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { + LocationComponent locationComponent = mapboxMap.getLocationComponent(); + locationComponent.activateLocationComponent(this, style); + locationComponent.setRenderMode(RenderMode.GPS); + locationComponent.setLocationComponentEnabled(false); + navigationMapRoute = new NavigationMapRoute(navigation, mapView, mapboxMap); + Snackbar.make(findViewById(R.id.container), "Tap map to place waypoint", + BaseTransientBottomBar.LENGTH_LONG).show(); + locationEngine = new ReplayRouteLocationEngine(); + newOrigin(); + }); } @Override - public void onMapClick(@NonNull LatLng point) { + public boolean onMapClick(@NonNull LatLng point) { if (destination == null) { destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); } else if (waypoint == null) { @@ -198,15 +200,30 @@ public void onMapClick(@NonNull LatLng point) { } mapboxMap.addMarker(new MarkerOptions().position(point)); calculateRoute(); + return true; } + @SuppressLint("MissingPermission") private void calculateRoute() { - Location userLocation = locationEngine.getLastLocation(); + locationEngine.getLastLocation(new LocationEngineCallback() { + @Override + public void onSuccess(LocationEngineResult result) { + findRouteWith(result); + } + + @Override + public void onFailure(@NonNull Exception exception) { + Timber.e(exception); + } + }); + } + + private void findRouteWith(LocationEngineResult result) { + Location userLocation = result.getLastLocation(); if (userLocation == null) { Timber.d("calculateRoute: User location is null, therefore, origin can't be set."); return; } - Point origin = Point.fromLngLat(userLocation.getLongitude(), userLocation.getLatitude()); if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) < 50) { startRouteButton.setVisibility(View.GONE); @@ -223,12 +240,11 @@ private void calculateRoute() { navigationRouteBuilder.build().getRoute(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(@NonNull Call call, @NonNull Response response) { Timber.d("Url: %s", call.request().url().toString()); if (response.body() != null) { if (!response.body().routes().isEmpty()) { - DirectionsRoute directionsRoute = response.body().routes().get(0); - MockNavigationActivity.this.route = directionsRoute; + MockNavigationActivity.this.route = response.body().routes().get(0); navigationMapRoute.addRoutes(response.body().routes()); startRouteButton.setVisibility(View.VISIBLE); } @@ -236,7 +252,7 @@ public void onResponse(Call call, Response call, Throwable throwable) { + public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { Timber.e(throwable, "onFailure: navigation.getRoute()"); } }); @@ -310,8 +326,6 @@ public void onLowMemory() { protected void onDestroy() { super.onDestroy(); navigation.onDestroy(); - locationEngine.removeLocationUpdates(); - locationEngine.deactivate(); if (mapboxMap != null) { mapboxMap.removeOnMapClickListener(this); } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/OfflineRegionDownloadActivity.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/OfflineRegionDownloadActivity.kt index 6bca5884ff8..ea9ad979690 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/OfflineRegionDownloadActivity.kt +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/OfflineRegionDownloadActivity.kt @@ -19,6 +19,7 @@ import android.widget.Toast import com.mapbox.geojson.BoundingBox import com.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.style.layers.FillLayer import com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor import com.mapbox.mapboxsdk.style.sources.GeoJsonSource @@ -113,17 +114,13 @@ class OfflineRegionDownloadActivity : AppCompatActivity(), RouteTileDownloadList private fun setupMapView(savedInstanceState: Bundle?) { mapView.onCreate(savedInstanceState) mapView.getMapAsync { mapboxMap -> + mapboxMap.setStyle(Style.LIGHT) { + it.addSource(GeoJsonSource("bounding-box-source")) + it.addLayer(FillLayer("bounding-box-layer", "bounding-box-source") + .withProperties(fillColor(Color.parseColor("#50667F")))) + } this.mapboxMap = mapboxMap mapboxMap.uiSettings.isRotateGesturesEnabled = false - addBoundingBoxToMap() - } - } - - private fun addBoundingBoxToMap() { - mapboxMap.apply { - addSource(GeoJsonSource("bounding-box-source")) - addLayer(FillLayer("bounding-box-layer", "bounding-box-source") - .withProperties(fillColor(Color.parseColor("#50667F")))) } } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/RerouteActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/RerouteActivity.java index 3ca8bfa35fe..2767ecb67aa 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/RerouteActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/RerouteActivity.java @@ -9,7 +9,8 @@ import android.view.View; import android.widget.Toast; -import com.mapbox.android.core.location.LocationEngineListener; +import com.mapbox.android.core.location.LocationEngineCallback; +import com.mapbox.android.core.location.LocationEngineResult; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.core.constants.Constants; @@ -27,6 +28,7 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView; import com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine; @@ -41,6 +43,7 @@ import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener; import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -51,9 +54,9 @@ import retrofit2.Response; import timber.log.Timber; -public class RerouteActivity extends HistoryActivity implements OnMapReadyCallback, LocationEngineListener, - Callback, MapboxMap.OnMapClickListener, NavigationEventListener, OffRouteListener, - ProgressChangeListener, MilestoneEventListener { +public class RerouteActivity extends HistoryActivity implements OnMapReadyCallback, + Callback, MapboxMap.OnMapClickListener, NavigationEventListener, + OffRouteListener, ProgressChangeListener, MilestoneEventListener { @BindView(R.id.mapView) MapView mapView; @@ -66,6 +69,8 @@ public class RerouteActivity extends HistoryActivity implements OnMapReadyCallba private Point destination = Point.fromLngLat(-0.383524, 39.497825); private Polyline polyline; + private final RerouteActivityLocationCallback callback = new RerouteActivityLocationCallback(this); + private Location lastLocation; private ReplayRouteLocationEngine mockLocationEngine; private MapboxNavigation navigation; private MapboxMap mapboxMap; @@ -141,47 +146,34 @@ protected void onDestroy() { @SuppressLint("MissingPermission") @Override - public void onMapReady(MapboxMap mapboxMap) { + public void onMapReady(@NonNull MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - mapboxMap.addOnMapClickListener(this); - - LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this); - locationComponent.setLocationComponentEnabled(true); - locationComponent.setRenderMode(RenderMode.GPS); - - mockLocationEngine = new ReplayRouteLocationEngine(); - mockLocationEngine.addLocationEngineListener(this); - navigation.setLocationEngine(mockLocationEngine); - - getRoute(origin, destination, null); + this.mapboxMap.addOnMapClickListener(this); + mapboxMap.setStyle(Style.DARK, style -> { + LocationComponent locationComponent = mapboxMap.getLocationComponent(); + locationComponent.activateLocationComponent(this, style); + locationComponent.setLocationComponentEnabled(true); + locationComponent.setRenderMode(RenderMode.GPS); + + mockLocationEngine = new ReplayRouteLocationEngine(); + getRoute(origin, destination); + }); } @Override - public void onConnected() { - // No-op - mock automatically begins pushing updates - } - - @Override - public void onLocationChanged(Location location) { - if (!tracking) { - mapboxMap.getLocationComponent().forceLocationUpdate(location); - } - } - - @Override - public void onMapClick(@NonNull LatLng point) { - if (!running || mapboxMap == null) { - return; + public boolean onMapClick(@NonNull LatLng point) { + if (!running || mapboxMap == null || lastLocation == null) { + return true; } mapboxMap.addMarker(new MarkerOptions().position(point)); mapboxMap.removeOnMapClickListener(this); - Point newDestination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); - mockLocationEngine.moveTo(newDestination); destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); + resetLocationEngine(destination); + tracking = false; + return true; } @Override @@ -195,8 +187,8 @@ public void onRunning(boolean running) { @Override public void userOffRoute(Location location) { - Point newOrigin = Point.fromLngLat(location.getLongitude(), location.getLatitude()); - getRoute(newOrigin, destination, location.getBearing()); + origin = Point.fromLngLat(lastLocation.getLongitude(), lastLocation.getLatitude()); + getRoute(origin, destination); Snackbar.make(contentLayout, "User Off Route", Snackbar.LENGTH_SHORT).show(); mapboxMap.addMarker(new MarkerOptions().position(new LatLng(location.getLatitude(), location.getLongitude()))); } @@ -204,6 +196,7 @@ public void userOffRoute(Location location) { @Override public void onProgressChange(Location location, RouteProgress routeProgress) { boolean isInTunnel = routeProgress.inTunnel(); + lastLocation = location; if (!wasInTunnel && isInTunnel) { wasInTunnel = true; Snackbar.make(contentLayout, "Enter tunnel!", Snackbar.LENGTH_SHORT).show(); @@ -230,11 +223,11 @@ public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Mi Snackbar.make(contentLayout, instruction, Snackbar.LENGTH_SHORT).show(); } instructionView.updateBannerInstructionsWith(milestone); - Timber.d("onMilestoneEvent - Current Instruction: " + instruction); + Timber.d("onMilestoneEvent - Current Instruction: %s", instruction); } @Override - public void onResponse(Call call, Response response) { + public void onResponse(@NonNull Call call, @NonNull Response response) { Timber.d(call.request().url().toString()); if (response.body() != null) { if (!response.body().routes().isEmpty()) { @@ -249,14 +242,19 @@ public void onResponse(Call call, Response call, Throwable throwable) { + public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { Timber.e(throwable); } - private void getRoute(Point origin, Point destination, Float bearing) { - Double heading = bearing == null ? null : bearing.doubleValue(); + void updateLocation(Location location) { + if (!tracking) { + mapboxMap.getLocationComponent().forceLocationUpdate(location); + } + } + + private void getRoute(Point origin, Point destination) { NavigationRoute.builder(this) - .origin(origin, heading, 90d) + .origin(origin) .destination(destination) .accessToken(Mapbox.getAccessToken()) .build().getRoute(this); @@ -281,16 +279,19 @@ private void drawRoute(DirectionsRoute route) { } } + private void resetLocationEngine(Point point) { + mockLocationEngine.moveTo(point); + navigation.setLocationEngine(mockLocationEngine); + } + private void resetLocationEngine(DirectionsRoute directionsRoute) { - mockLocationEngine.deactivate(); mockLocationEngine.assign(directionsRoute); + navigation.setLocationEngine(mockLocationEngine); } private void shutdownLocationEngine() { if (mockLocationEngine != null) { - mockLocationEngine.removeLocationEngineListener(this); - mockLocationEngine.removeLocationUpdates(); - mockLocationEngine.deactivate(); + mockLocationEngine.removeLocationUpdates(callback); } } @@ -299,4 +300,30 @@ private void shutdownNavigation() { navigation.removeProgressChangeListener(this); navigation.onDestroy(); } + + private static class RerouteActivityLocationCallback implements LocationEngineCallback { + + private final WeakReference activityWeakReference; + + RerouteActivityLocationCallback(RerouteActivity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onSuccess(LocationEngineResult result) { + RerouteActivity activity = activityWeakReference.get(); + if (activity != null) { + Location location = result.getLastLocation(); + if (location == null) { + return; + } + activity.updateLocation(location); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Timber.e(exception); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/ForwardingLocationCallback.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/ForwardingLocationCallback.java deleted file mode 100644 index eeec7bbf064..00000000000 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/ForwardingLocationCallback.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.mapbox.services.android.navigation.testapp.activity.location; - -import android.location.Location; - -import com.google.android.gms.location.LocationCallback; -import com.google.android.gms.location.LocationResult; - -import java.util.List; - -class ForwardingLocationCallback extends LocationCallback { - - private static final int FIRST = 0; - private final FusedLocationEngine locationEngine; - - ForwardingLocationCallback(FusedLocationEngine locationEngine) { - this.locationEngine = locationEngine; - } - - @Override - public void onLocationResult(LocationResult locationResult) { - List locations = locationResult.getLocations(); - boolean hasLocation = !locations.isEmpty(); - if (hasLocation) { - Location newLocation = locations.get(FIRST); - locationEngine.notifyListenersOnLocationChanged(newLocation); - } - } -} diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/FusedLocationEngine.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/FusedLocationEngine.java deleted file mode 100644 index 30188bc0114..00000000000 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/FusedLocationEngine.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.mapbox.services.android.navigation.testapp.activity.location; - -import android.content.Context; -import android.location.Location; -import android.os.Looper; -import android.support.annotation.NonNull; - -import com.google.android.gms.common.api.ApiException; -import com.google.android.gms.location.FusedLocationProviderClient; -import com.google.android.gms.location.LocationRequest; -import com.google.android.gms.location.LocationServices; -import com.google.android.gms.location.LocationSettingsRequest; -import com.google.android.gms.location.LocationSettingsStatusCodes; -import com.google.android.gms.location.SettingsClient; -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; - -import timber.log.Timber; - -public class FusedLocationEngine extends LocationEngine { - - private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000; - private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; - private FusedLocationProviderClient fusedLocationClient; - private SettingsClient settingsClient; - private LocationRequest locationRequest; - private LocationSettingsRequest locationSettingsRequest; - private boolean isConnected = false; - private boolean receivingUpdates = false; - private Location lastLocation = null; - private final ForwardingLocationCallback forwardingCallback = new ForwardingLocationCallback(this); - - public FusedLocationEngine(@NonNull Context context) { - super(); - fusedLocationClient = LocationServices.getFusedLocationProviderClient(context); - settingsClient = LocationServices.getSettingsClient(context); - } - - @Override - public void activate() { - if (!isConnected) { - startLocationUpdates(); - } - } - - @Override - public void deactivate() { - stopLocationUpdates(); - isConnected = false; - } - - @Override - public boolean isConnected() { - return isConnected; - } - - @Override - @SuppressWarnings("MissingPermission") - public Location getLastLocation() { - fusedLocationClient.getLastLocation().addOnSuccessListener(location -> lastLocation = location); - return lastLocation; - } - - @Override - @SuppressWarnings( {"MissingPermission"}) - public void requestLocationUpdates() { - if (isConnected && !receivingUpdates) { - fusedLocationClient.requestLocationUpdates(locationRequest, forwardingCallback, Looper.myLooper()) - .addOnSuccessListener(aVoid -> receivingUpdates = true); - } - } - - @Override - public void removeLocationUpdates() { - stopLocationUpdates(); - } - - @Override - public Type obtainType() { - return Type.GOOGLE_PLAY_SERVICES; - } - - void notifyListenersOnLocationChanged(Location location) { - for (LocationEngineListener listener : locationListeners) { - listener.onLocationChanged(location); - } - } - - private void createLocationRequest() { - locationRequest = new LocationRequest(); - //TODO: unhardcode these - locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); - locationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); - locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); - } - - private void buildLocationSettingsRequest() { - LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); - builder.addLocationRequest(locationRequest); - locationSettingsRequest = builder.build(); - } - - private void startLocationUpdates() { - createLocationRequest(); - buildLocationSettingsRequest(); - settingsClient.checkLocationSettings(locationSettingsRequest) - .addOnSuccessListener(locationSettingsResponse -> { - isConnected = true; - notifyListenersOnConnected(); - }) - .addOnFailureListener(exception -> { - isConnected = false; - int statusCode = ((ApiException) exception).getStatusCode(); - switch (statusCode) { - case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: - Timber.e("Location settings are not satisfied. Upgrade location settings"); - break; - case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: - Timber.e("Location settings are inadequate, and cannot be fixed here. Fix in Settings."); - break; - default: - break; - } - }); - } - - private void notifyListenersOnConnected() { - for (LocationEngineListener listener : locationListeners) { - listener.onConnected(); - } - } - - private void stopLocationUpdates() { - fusedLocationClient.removeLocationUpdates(forwardingCallback) - .addOnCompleteListener(task -> receivingUpdates = false); - } -} diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/ComponentNavigationActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/ComponentNavigationActivity.java index 20eefebb1aa..1e15bdef18a 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/ComponentNavigationActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/ComponentNavigationActivity.java @@ -17,8 +17,10 @@ import android.view.View; import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; -import com.mapbox.android.core.location.LocationEnginePriority; +import com.mapbox.android.core.location.LocationEngineCallback; +import com.mapbox.android.core.location.LocationEngineProvider; +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.android.core.location.LocationEngineResult; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.geojson.Point; @@ -30,9 +32,9 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.testapp.activity.HistoryActivity; -import com.mapbox.services.android.navigation.testapp.activity.location.FusedLocationEngine; import com.mapbox.services.android.navigation.ui.v5.camera.DynamicCamera; import com.mapbox.services.android.navigation.ui.v5.camera.NavigationCamera; import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionView; @@ -51,6 +53,7 @@ import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress; import java.io.File; +import java.lang.ref.WeakReference; import java.util.List; import java.util.Locale; @@ -64,8 +67,7 @@ import timber.log.Timber; public class ComponentNavigationActivity extends HistoryActivity implements OnMapReadyCallback, - MapboxMap.OnMapLongClickListener, LocationEngineListener, ProgressChangeListener, - MilestoneEventListener, OffRouteListener { + MapboxMap.OnMapLongClickListener, ProgressChangeListener, MilestoneEventListener, OffRouteListener { private static final int FIRST = 0; private static final int ONE_HUNDRED_MILLISECONDS = 100; @@ -80,7 +82,8 @@ public class ComponentNavigationActivity extends HistoryActivity implements OnMa private static final double DEFAULT_ZOOM = 12.0; private static final double DEFAULT_TILT = 0d; private static final double DEFAULT_BEARING = 0d; - private static final int ONE_SECOND_INTERVAL = 1000; + private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000; + private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; @BindView(R.id.componentNavigationLayout) ConstraintLayout navigationLayout; @@ -97,6 +100,7 @@ public class ComponentNavigationActivity extends HistoryActivity implements OnMa @BindView(R.id.cancelNavigationFab) FloatingActionButton cancelNavigationFab; + private final ComponentActivityLocationCallback callback = new ComponentActivityLocationCallback(this); private LocationEngine locationEngine; private MapboxNavigation navigation; private NavigationSpeechPlayer speechPlayer; @@ -125,26 +129,28 @@ protected void onCreate(Bundle savedInstanceState) { } @Override - public void onMapReady(MapboxMap mapboxMap) { - mapState = MapState.INFO; - navigationMap = new NavigationMapboxMap(mapView, mapboxMap); + public void onMapReady(@NonNull MapboxMap mapboxMap) { + mapboxMap.setStyle(new Style.Builder().fromUrl(getString(R.string.navigation_guidance_day)), style -> { + mapState = MapState.INFO; + navigationMap = new NavigationMapboxMap(mapView, mapboxMap); - // For Location updates - initializeLocationEngine(); + // For Location updates + initializeLocationEngine(); - // For navigation logic / processing - initializeNavigation(mapboxMap); - navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE); + // For navigation logic / processing + initializeNavigation(mapboxMap); + navigationMap.updateCameraTrackingMode(NavigationCamera.NAVIGATION_TRACKING_MODE_NONE); - // For voice instructions - initializeSpeechPlayer(); + // For voice instructions + initializeSpeechPlayer(); + }); } @Override - public void onMapLongClick(@NonNull LatLng point) { + public boolean onMapLongClick(@NonNull LatLng point) { // Only reverse geocode while we are not in navigation if (mapState.equals(MapState.NAVIGATION)) { - return; + return true; } // Fetch the route with this given point @@ -158,6 +164,7 @@ public void onMapLongClick(@NonNull LatLng point) { // Update camera to new destination moveCameraToInclude(destination); vibrate(); + return true; } @OnClick(R.id.startNavigationFab) @@ -200,31 +207,6 @@ public void onCancelNavigationClick(FloatingActionButton floatingActionButton) { addLocationEngineListener(); } - /* - * LocationEngine listeners - */ - - @SuppressLint("MissingPermission") - @Override - public void onConnected() { - locationEngine.requestLocationUpdates(); - } - - @Override - public void onLocationChanged(Location location) { - if (lastLocation == null) { - // Move the navigationMap camera to the first Location - moveCameraTo(location); - - // Allow navigationMap clicks now that we have the current Location - navigationMap.retrieveMap().addOnMapLongClickListener(this); - showSnackbar(LONG_PRESS_MAP_MESSAGE, BaseTransientBottomBar.LENGTH_LONG); - } - - // Cache for fetching the route later - updateLocation(location); - } - /* * Navigation listeners */ @@ -315,6 +297,20 @@ protected void onDestroy() { navigation.onDestroy(); } + void checkFirstUpdate(Location location) { + if (lastLocation == null) { + moveCameraTo(location); + // Allow navigationMap clicks now that we have the current Location + navigationMap.retrieveMap().addOnMapLongClickListener(this); + showSnackbar(LONG_PRESS_MAP_MESSAGE, BaseTransientBottomBar.LENGTH_LONG); + } + } + + void updateLocation(Location location) { + lastLocation = location; + navigationMap.updateLocation(location); + } + private void initializeSpeechPlayer() { String english = Locale.US.getLanguage(); Cache cache = new Cache(new File(getApplication().getCacheDir(), COMPONENT_NAVIGATION_INSTRUCTION_CACHE), @@ -326,13 +322,11 @@ private void initializeSpeechPlayer() { speechPlayer = new NavigationSpeechPlayer(speechPlayerProvider); } + @SuppressLint("MissingPermission") private void initializeLocationEngine() { - locationEngine = new FusedLocationEngine(getApplicationContext()); - locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); - locationEngine.addLocationEngineListener(this); - locationEngine.setInterval(ONE_SECOND_INTERVAL); - locationEngine.setFastestInterval(500); - locationEngine.activate(); + locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext()); + LocationEngineRequest request = buildEngineRequest(); + locationEngine.requestLocationUpdates(request, callback, null); showSnackbar(SEARCHING_FOR_GPS_MESSAGE, BaseTransientBottomBar.LENGTH_SHORT); } @@ -360,11 +354,6 @@ private void playAnnouncement(Milestone milestone) { } } - private void updateLocation(Location location) { - lastLocation = location; - navigationMap.updateLocation(location); - } - private void moveCameraTo(Location location) { CameraPosition cameraPosition = buildCameraPositionFrom(location, location.getBearing()); navigationMap.retrieveMap().animateCamera( @@ -424,13 +413,15 @@ private void resetMapAfterNavigation() { private void removeLocationEngineListener() { if (locationEngine != null) { - locationEngine.removeLocationEngineListener(this); + locationEngine.removeLocationUpdates(callback); } } + @SuppressLint("MissingPermission") private void addLocationEngineListener() { if (locationEngine != null) { - locationEngine.addLocationEngineListener(this); + LocationEngineRequest request = buildEngineRequest(); + locationEngine.requestLocationUpdates(request, callback, null); } } @@ -477,4 +468,43 @@ private void vibrate() { vibrator.vibrate(ONE_HUNDRED_MILLISECONDS); } } + + @NonNull + private LocationEngineRequest buildEngineRequest() { + return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) + .build(); + } + + /* + * LocationEngine callback + */ + + private static class ComponentActivityLocationCallback implements LocationEngineCallback { + + private final WeakReference activityWeakReference; + + ComponentActivityLocationCallback(ComponentNavigationActivity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onSuccess(LocationEngineResult result) { + ComponentNavigationActivity activity = activityWeakReference.get(); + if (activity != null) { + Location location = result.getLastLocation(); + if (location == null) { + return; + } + activity.checkFirstUpdate(location); + activity.updateLocation(location); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Timber.e(exception); + } + } } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/DualNavigationMapActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/DualNavigationMapActivity.java index 0a1f85e6df5..2b34a4ecfc6 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/DualNavigationMapActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/DualNavigationMapActivity.java @@ -1,5 +1,6 @@ package com.mapbox.services.android.navigation.testapp.activity.navigationui; +import android.annotation.SuppressLint; import android.location.Location; import android.os.Bundle; import android.support.annotation.NonNull; @@ -13,13 +14,15 @@ import android.widget.ProgressBar; import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; +import com.mapbox.android.core.location.LocationEngineCallback; import com.mapbox.android.core.location.LocationEngineProvider; +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.android.core.location.LocationEngineResult; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.LocationComponent; @@ -27,6 +30,7 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.ui.v5.NavigationView; import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions; @@ -36,18 +40,22 @@ import com.mapbox.services.android.navigation.ui.v5.route.OnRouteSelectionChangeListener; import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute; +import java.lang.ref.WeakReference; + import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; - -import static com.mapbox.android.core.location.LocationEnginePriority.HIGH_ACCURACY; +import timber.log.Timber; public class DualNavigationMapActivity extends AppCompatActivity implements OnNavigationReadyCallback, NavigationListener, Callback, OnMapReadyCallback, MapboxMap.OnMapLongClickListener, - LocationEngineListener, OnRouteSelectionChangeListener { + OnRouteSelectionChangeListener { private static final int CAMERA_ANIMATION_DURATION = 1000; private static final int DEFAULT_CAMERA_ZOOM = 16; + private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000; + private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; + private final DualNavigationLocationCallback callback = new DualNavigationLocationCallback(this); private ConstraintLayout dualNavigationMap; private NavigationView navigationView; private MapView mapView; @@ -90,23 +98,26 @@ public void onNavigationReady(boolean isRunning) { } @Override - public void onMapReady(MapboxMap mapboxMap) { + public void onMapReady(@NonNull MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; this.mapboxMap.addOnMapLongClickListener(this); - initLocationEngine(); - initializeLocationLayer(); - initMapRoute(); - fetchRoute(); + mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { + initializeLocationEngine(); + initializeLocationComponent(style); + initMapRoute(); + fetchRoute(); + }); } @Override - public void onMapLongClick(@NonNull LatLng point) { + public boolean onMapLongClick(@NonNull LatLng point) { destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); updateLoadingTo(true); setCurrentMarkerPosition(point); if (origin != null) { fetchRoute(); } + return true; } @Override @@ -140,18 +151,6 @@ public void onNavigationFinished() { public void onNavigationRunning() { } - @SuppressWarnings( {"MissingPermission"}) - @Override - public void onConnected() { - locationEngine.requestLocationUpdates(); - } - - @Override - public void onLocationChanged(Location location) { - origin = Point.fromLngLat(location.getLongitude(), location.getLatitude()); - onLocationFound(location); - } - @Override public void onNewPrimaryRouteSelected(DirectionsRoute directionsRoute) { route = directionsRoute; @@ -164,16 +163,15 @@ public void onStart() { mapView.onStart(); } + @SuppressLint("MissingPermission") @Override public void onResume() { super.onResume(); navigationView.onResume(); mapView.onResume(); if (locationEngine != null) { - locationEngine.addLocationEngineListener(this); - if (!locationEngine.isConnected()) { - locationEngine.activate(); - } + LocationEngineRequest request = buildEngineRequest(); + locationEngine.requestLocationUpdates(request, callback, null); } } @@ -210,7 +208,7 @@ public void onPause() { navigationView.onPause(); mapView.onPause(); if (locationEngine != null) { - locationEngine.removeLocationEngineListener(this); + locationEngine.removeLocationUpdates(callback); } } @@ -226,9 +224,14 @@ protected void onDestroy() { super.onDestroy(); navigationView.onDestroy(); mapView.onDestroy(); - if (locationEngine != null) { - locationEngine.removeLocationUpdates(); - locationEngine.deactivate(); + } + + void onLocationFound(Location location) { + origin = Point.fromLngLat(location.getLongitude(), location.getLatitude()); + if (!locationFound) { + animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); + locationFound = true; + updateLoadingTo(false); } } @@ -287,27 +290,24 @@ private boolean validRouteResponse(Response response) { return response.body() != null && !response.body().routes().isEmpty(); } + @SuppressWarnings("MissingPermission") + private void initializeLocationEngine() { + locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext()); + locationEngine.getLastLocation(callback); + } - @SuppressWarnings( {"MissingPermission"}) - private void initLocationEngine() { - locationEngine = new LocationEngineProvider(this).obtainBestLocationEngineAvailable(); - locationEngine.setPriority(HIGH_ACCURACY); - locationEngine.setInterval(0); - locationEngine.setFastestInterval(1000); - locationEngine.addLocationEngineListener(this); - locationEngine.activate(); - - if (locationEngine.getLastLocation() != null) { - Location lastLocation = locationEngine.getLastLocation(); - onLocationChanged(lastLocation); - origin = Point.fromLngLat(lastLocation.getLongitude(), lastLocation.getLatitude()); - } + @NonNull + private LocationEngineRequest buildEngineRequest() { + return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) + .build(); } - @SuppressWarnings( {"MissingPermission"}) - private void initializeLocationLayer() { + @SuppressLint("MissingPermission") + private void initializeLocationComponent(Style style) { LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this, locationEngine); + locationComponent.activateLocationComponent(this, style, locationEngine); locationComponent.setLocationComponentEnabled(true); locationComponent.setRenderMode(RenderMode.COMPASS); } @@ -320,7 +320,7 @@ private void initMapRoute() { private void setCurrentMarkerPosition(LatLng position) { if (position != null) { if (currentMarker == null) { - MarkerViewOptions markerViewOptions = new MarkerViewOptions() + MarkerOptions markerViewOptions = new MarkerOptions() .position(position); currentMarker = mapboxMap.addMarker(markerViewOptions); } else { @@ -329,15 +329,33 @@ private void setCurrentMarkerPosition(LatLng position) { } } - private void onLocationFound(Location location) { - if (!locationFound) { - animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); - locationFound = true; - updateLoadingTo(false); - } - } - private void animateCamera(LatLng point) { mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, DEFAULT_CAMERA_ZOOM), CAMERA_ANIMATION_DURATION); } + + private static class DualNavigationLocationCallback implements LocationEngineCallback { + + private final WeakReference activityWeakReference; + + DualNavigationLocationCallback(DualNavigationMapActivity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onSuccess(LocationEngineResult result) { + DualNavigationMapActivity activity = activityWeakReference.get(); + if (activity != null) { + Location location = result.getLastLocation(); + if (location == null) { + return; + } + activity.onLocationFound(location); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Timber.e(exception); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java index 5c770e3ef37..549e68b06cf 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationLauncherActivity.java @@ -18,8 +18,10 @@ import android.widget.Toast; import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; +import com.mapbox.android.core.location.LocationEngineCallback; import com.mapbox.android.core.location.LocationEngineProvider; +import com.mapbox.android.core.location.LocationEngineRequest; +import com.mapbox.android.core.location.LocationEngineResult; import com.mapbox.api.directions.v5.DirectionsCriteria; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; @@ -28,7 +30,7 @@ import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; @@ -39,6 +41,7 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.NavigationSettingsActivity; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.ui.v5.NavigationLauncher; @@ -48,6 +51,7 @@ import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute; import com.mapbox.services.android.navigation.v5.utils.LocaleUtils; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -57,17 +61,19 @@ import butterknife.OnClick; import retrofit2.Call; import retrofit2.Response; - -import static com.mapbox.android.core.location.LocationEnginePriority.HIGH_ACCURACY; +import timber.log.Timber; public class NavigationLauncherActivity extends AppCompatActivity implements OnMapReadyCallback, - MapboxMap.OnMapLongClickListener, LocationEngineListener, OnRouteSelectionChangeListener { + MapboxMap.OnMapLongClickListener, OnRouteSelectionChangeListener { private static final int CAMERA_ANIMATION_DURATION = 1000; private static final int DEFAULT_CAMERA_ZOOM = 16; private static final int CHANGE_SETTING_REQUEST_CODE = 1; private static final int INITIAL_ZOOM = 16; + private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000; + private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500; + private final NavigationLauncherLocationCallback callback = new NavigationLauncherLocationCallback(this); private LocationEngine locationEngine; private NavigationMapRoute mapRoute; private MapboxMap mapboxMap; @@ -115,10 +121,6 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - private void showSettings() { - startActivityForResult(new Intent(this, NavigationSettingsActivity.class), CHANGE_SETTING_REQUEST_CODE); - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -143,10 +145,7 @@ public void onResume() { super.onResume(); mapView.onResume(); if (locationEngine != null) { - locationEngine.addLocationEngineListener(this); - if (!locationEngine.isConnected()) { - locationEngine.activate(); - } + locationEngine.requestLocationUpdates(buildEngineRequest(), callback, null); } } @@ -155,7 +154,7 @@ public void onPause() { super.onPause(); mapView.onPause(); if (locationEngine != null) { - locationEngine.removeLocationEngineListener(this); + locationEngine.removeLocationUpdates(callback); } } @@ -175,10 +174,6 @@ protected void onStop() { protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); - if (locationEngine != null) { - locationEngine.removeLocationUpdates(); - locationEngine.deactivate(); - } } @Override @@ -195,14 +190,16 @@ public void onRouteLaunchClick() { @Override public void onMapReady(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - this.mapboxMap.addOnMapLongClickListener(this); - initLocationEngine(); - initializeLocationComponent(); - initMapRoute(); + mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> { + mapboxMap.addOnMapLongClickListener(this); + initializeLocationEngine(); + initializeLocationComponent(style); + initializeMapRoute(); + }); } @Override - public void onMapLongClick(@NonNull LatLng point) { + public boolean onMapLongClick(@NonNull LatLng point) { destination = Point.fromLngLat(point.getLongitude(), point.getLatitude()); launchRouteBtn.setEnabled(false); loading.setVisibility(View.VISIBLE); @@ -210,50 +207,48 @@ public void onMapLongClick(@NonNull LatLng point) { if (currentLocation != null) { fetchRoute(); } + return true; } - @SuppressWarnings( {"MissingPermission"}) @Override - public void onConnected() { - locationEngine.requestLocationUpdates(); + public void onNewPrimaryRouteSelected(DirectionsRoute directionsRoute) { + route = directionsRoute; } - @Override - public void onLocationChanged(Location location) { - currentLocation = Point.fromLngLat(location.getLongitude(), location.getLatitude()); - onLocationFound(location); + void updateCurrentLocation(Point currentLocation) { + this.currentLocation = currentLocation; } - @Override - public void onNewPrimaryRouteSelected(DirectionsRoute directionsRoute) { - route = directionsRoute; + void onLocationFound(Location location) { + if (!locationFound) { + animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); + Snackbar.make(mapView, R.string.explanation_long_press_waypoint, Snackbar.LENGTH_LONG).show(); + locationFound = true; + hideLoading(); + } + } + + private void showSettings() { + startActivityForResult(new Intent(this, NavigationSettingsActivity.class), CHANGE_SETTING_REQUEST_CODE); } @SuppressWarnings( {"MissingPermission"}) - private void initLocationEngine() { - locationEngine = new LocationEngineProvider(this).obtainBestLocationEngineAvailable(); - locationEngine.setPriority(HIGH_ACCURACY); - locationEngine.setInterval(0); - locationEngine.setFastestInterval(1000); - locationEngine.addLocationEngineListener(this); - locationEngine.activate(); - - if (locationEngine.getLastLocation() != null) { - Location lastLocation = locationEngine.getLastLocation(); - onLocationChanged(lastLocation); - currentLocation = Point.fromLngLat(lastLocation.getLongitude(), lastLocation.getLatitude()); - } + private void initializeLocationEngine() { + locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext()); + LocationEngineRequest request = buildEngineRequest(); + locationEngine.requestLocationUpdates(request, callback, null); + locationEngine.getLastLocation(callback); } @SuppressWarnings( {"MissingPermission"}) - private void initializeLocationComponent() { + private void initializeLocationComponent(Style style) { LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this, locationEngine); + locationComponent.activateLocationComponent(this, style, locationEngine); locationComponent.setLocationComponentEnabled(true); locationComponent.setRenderMode(RenderMode.COMPASS); } - private void initMapRoute() { + private void initializeMapRoute() { mapRoute = new NavigationMapRoute(mapView, mapboxMap); mapRoute.setOnRouteSelectionChangeListener(this); } @@ -353,15 +348,6 @@ private void hideLoading() { } } - private void onLocationFound(Location location) { - if (!locationFound) { - animateCamera(new LatLng(location.getLatitude(), location.getLongitude())); - Snackbar.make(mapView, R.string.explanation_long_press_waypoint, Snackbar.LENGTH_LONG).show(); - locationFound = true; - hideLoading(); - } - } - public void boundCameraToRoute() { if (route != null) { List routeCoords = LineString.fromPolyline(route.geometry(), @@ -395,7 +381,7 @@ private void animateCamera(LatLng point) { private void setCurrentMarkerPosition(LatLng position) { if (position != null) { if (currentMarker == null) { - MarkerViewOptions markerViewOptions = new MarkerViewOptions() + MarkerOptions markerViewOptions = new MarkerOptions() .position(position); currentMarker = mapboxMap.addMarker(markerViewOptions); } else { @@ -403,4 +389,39 @@ private void setCurrentMarkerPosition(LatLng position) { } } } + + @NonNull + private LocationEngineRequest buildEngineRequest() { + return new LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) + .build(); + } + + private static class NavigationLauncherLocationCallback implements LocationEngineCallback { + + private final WeakReference activityWeakReference; + + NavigationLauncherLocationCallback(NavigationLauncherActivity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + @Override + public void onSuccess(LocationEngineResult result) { + NavigationLauncherActivity activity = activityWeakReference.get(); + if (activity != null) { + Location location = result.getLastLocation(); + if (location == null) { + return; + } + activity.updateCurrentLocation(Point.fromLngLat(location.getLongitude(), location.getLatitude())); + activity.onLocationFound(location); + } + } + + @Override + public void onFailure(@NonNull Exception exception) { + Timber.e(exception); + } + } } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationMapRouteActivity.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationMapRouteActivity.java index 4378394814d..6e42bcbe77a 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationMapRouteActivity.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/navigationui/NavigationMapRouteActivity.java @@ -19,7 +19,6 @@ import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; -import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.LocationComponent; import com.mapbox.mapboxsdk.location.modes.CameraMode; @@ -27,6 +26,7 @@ import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.services.android.navigation.testapp.R; import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute; import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute; @@ -66,7 +66,6 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_navigation_map_route); ButterKnife.bind(this); - mapView.setStyleUrl(styleCycle.getStyle()); mapView.onCreate(savedInstanceState); mapView.getMapAsync(this); } @@ -74,7 +73,7 @@ protected void onCreate(Bundle savedInstanceState) { @OnClick(R.id.fabStyles) public void onStyleFabClick() { if (mapboxMap != null) { - mapboxMap.setStyleUrl(styleCycle.getNextStyle()); + mapboxMap.setStyle(styleCycle.getNextStyle()); } } @@ -87,15 +86,18 @@ public void onRemoveRouteClick(View fabRemoveRoute) { @Override public void onMapReady(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - initializeLocationComponent(mapboxMap); - navigationMapRoute = new NavigationMapRoute(null, mapView, mapboxMap); - mapboxMap.addOnMapLongClickListener(this); - Snackbar.make(mapView, "Long press to select route", Snackbar.LENGTH_SHORT).show(); + mapboxMap.setStyle(styleCycle.getStyle(), style -> { + initializeLocationComponent(mapboxMap); + navigationMapRoute = new NavigationMapRoute(null, mapView, mapboxMap); + mapboxMap.addOnMapLongClickListener(this); + Snackbar.make(mapView, "Long press to select route", Snackbar.LENGTH_SHORT).show(); + }); } @Override - public void onMapLongClick(@NonNull LatLng point) { + public boolean onMapLongClick(@NonNull LatLng point) { handleClicked(point); + return true; } @Override @@ -166,7 +168,7 @@ protected void onSaveInstanceState(Bundle outState) { @SuppressWarnings("MissingPermission") private void initializeLocationComponent(MapboxMap mapboxMap) { LocationComponent locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(this); + locationComponent.activateLocationComponent(this, mapboxMap.getStyle()); locationComponent.setLocationComponentEnabled(true); locationComponent.setRenderMode(RenderMode.COMPASS); locationComponent.setCameraMode(CameraMode.TRACKING); diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleActivity.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleActivity.kt index 6191c157ce2..db1904290ad 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleActivity.kt +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleActivity.kt @@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds import com.mapbox.mapboxsdk.location.modes.RenderMode import com.mapbox.mapboxsdk.maps.AttributionDialogManager import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.Style import com.mapbox.services.android.navigation.testapp.NavigationSettingsActivity import com.mapbox.services.android.navigation.testapp.R import com.mapbox.services.android.navigation.testapp.activity.HistoryActivity @@ -109,12 +110,14 @@ class ExampleActivity : HistoryActivity(), ExampleView { } override fun onMapReady(mapboxMap: MapboxMap) { - map = NavigationMapboxMap(mapView, mapboxMap) - map?.setOnRouteSelectionChangeListener(this) - map?.updateLocationLayerRenderMode(RenderMode.NORMAL) - mapboxMap.addOnMapLongClickListener { presenter.onMapLongClick(it) } - presenter.buildDynamicCameraFrom(mapboxMap) - resetMapPadding() // Ignore navigation padding default + mapboxMap.setStyle(Style.Builder().fromUrl(getString(R.string.navigation_guidance_day))) { + map = NavigationMapboxMap(mapView, mapboxMap) + map?.setOnRouteSelectionChangeListener(this) + map?.updateLocationLayerRenderMode(RenderMode.NORMAL) + mapboxMap.addOnMapLongClickListener { point -> presenter.onMapLongClick(point) } + presenter.buildDynamicCameraFrom(mapboxMap) + resetMapPadding() // Ignore navigation padding default + } } override fun onFeatureClicked(feature: CarmenFeature) { @@ -151,9 +154,11 @@ class ExampleActivity : HistoryActivity(), ExampleView { } override fun updateMapCameraFor(bounds: LatLngBounds, padding: IntArray, duration: Int) { - map?.retrieveMap()?.let { - val position = it.getCameraForLatLngBounds(bounds, padding) - it.animateCamera(CameraUpdateFactory.newCameraPosition(position), duration) + map?.retrieveMap()?.let { map -> + val position = map.getCameraForLatLngBounds(bounds, padding) + position?.let { + map.animateCamera(CameraUpdateFactory.newCameraPosition(it), duration) + } } } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleLocationEngineCallback.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleLocationEngineCallback.kt new file mode 100644 index 00000000000..0ba565c5def --- /dev/null +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleLocationEngineCallback.kt @@ -0,0 +1,19 @@ +package com.mapbox.services.android.navigation.testapp.example.ui + +import android.arch.lifecycle.MutableLiveData +import android.location.Location +import com.mapbox.android.core.location.LocationEngineCallback +import com.mapbox.android.core.location.LocationEngineResult +import timber.log.Timber + +class ExampleLocationEngineCallback(private val location: MutableLiveData): + LocationEngineCallback { + + override fun onSuccess(result: LocationEngineResult) { + location.value = result.lastLocation + } + + override fun onFailure(exception: Exception) { + Timber.e(exception) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExamplePresenter.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExamplePresenter.kt index 1432f6ad1f4..ccd2e31d9aa 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExamplePresenter.kt +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExamplePresenter.kt @@ -197,8 +197,9 @@ class ExamplePresenter(private val view: ExampleView, private val viewModel: Exa } } - fun onMapLongClick(point: LatLng) { + fun onMapLongClick(point: LatLng): Boolean { viewModel.reverseGeocode(point) + return true } fun onBackPressed(): Boolean { diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleViewModel.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleViewModel.kt index 64289a05762..1cb02ce0daf 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleViewModel.kt +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/ExampleViewModel.kt @@ -1,12 +1,14 @@ package com.mapbox.services.android.navigation.testapp.example.ui +import android.annotation.SuppressLint import android.app.Application import android.arch.lifecycle.AndroidViewModel import android.arch.lifecycle.MutableLiveData import android.location.Location import android.preference.PreferenceManager import com.mapbox.android.core.location.LocationEngine -import com.mapbox.android.core.location.LocationEnginePriority +import com.mapbox.android.core.location.LocationEngineProvider +import com.mapbox.android.core.location.LocationEngineRequest import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.geocoding.v5.GeocodingCriteria import com.mapbox.api.geocoding.v5.MapboxGeocoding @@ -16,8 +18,10 @@ import com.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.services.android.navigation.testapp.NavigationApplication.Companion.instance import com.mapbox.services.android.navigation.testapp.R -import com.mapbox.services.android.navigation.testapp.activity.location.FusedLocationEngine -import com.mapbox.services.android.navigation.testapp.example.ui.navigation.* +import com.mapbox.services.android.navigation.testapp.example.ui.navigation.ExampleMilestoneEventListener +import com.mapbox.services.android.navigation.testapp.example.ui.navigation.ExampleOffRouteListener +import com.mapbox.services.android.navigation.testapp.example.ui.navigation.ExampleProgressChangeListener +import com.mapbox.services.android.navigation.testapp.example.ui.navigation.RouteFinder import com.mapbox.services.android.navigation.ui.v5.camera.DynamicCamera import com.mapbox.services.android.navigation.ui.v5.voice.NavigationSpeechPlayer import com.mapbox.services.android.navigation.ui.v5.voice.SpeechPlayerProvider @@ -33,7 +37,8 @@ import timber.log.Timber import java.io.File import java.util.Locale.US -private const val ONE_SECOND_INTERVAL = 1000 +private const val UPDATE_INTERVAL_IN_MILLISECONDS: Long = 1000 +private const val FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS: Long = 500 private const val EXAMPLE_INSTRUCTION_CACHE = "example-navigation-instruction-cache" private const val TEN_MEGABYTE_CACHE_SIZE: Long = 10 * 1024 * 1024 @@ -51,7 +56,7 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) var isOffRoute: Boolean = false private val locationEngine: LocationEngine - private val locationEngineListener: ExampleLocationEngineListener + private val locationEngineCallback: ExampleLocationEngineCallback private val speechPlayer: NavigationSpeechPlayer private val navigation: MapboxNavigation @@ -61,11 +66,8 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) init { routeFinder = RouteFinder(this, routes, accessToken, retrieveOfflineVersionFromPreferences()) // Initialize the location engine - locationEngine = FusedLocationEngine(getApplication()) - locationEngineListener = ExampleLocationEngineListener(locationEngine, location) - locationEngine.addLocationEngineListener(locationEngineListener) - locationEngine.priority = LocationEnginePriority.HIGH_ACCURACY - locationEngine.fastestInterval = ONE_SECOND_INTERVAL + locationEngine = LocationEngineProvider.getBestLocationEngine(getApplication()) + locationEngineCallback = ExampleLocationEngineCallback(location) // Initialize navigation and pass the LocationEngine navigation = MapboxNavigation(getApplication(), accessToken) @@ -74,7 +76,7 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) // Initialize the speech player and pass to milestone event listener for instructions val english = US.language // TODO localization val cache = Cache(File(application.cacheDir, EXAMPLE_INSTRUCTION_CACHE), - TEN_MEGABYTE_CACHE_SIZE) + TEN_MEGABYTE_CACHE_SIZE) val voiceInstructionLoader = VoiceInstructionLoader(getApplication(), accessToken, cache) val speechPlayerProvider = SpeechPlayerProvider(getApplication(), english, true, voiceInstructionLoader) speechPlayer = NavigationSpeechPlayer(speechPlayerProvider) @@ -89,7 +91,7 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) } fun activateLocationEngine() { - locationEngine.activate() + requestLocation() } fun findRouteToDestination() { @@ -111,12 +113,12 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) fun startNavigation() { primaryRoute?.let { navigation.startNavigation(it) - removeLocationEngineListener() + removeLocation() } } fun stopNavigation() { - addLocationEngineListener() + requestLocation() navigation.stopNavigation() } @@ -126,10 +128,10 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) fun reverseGeocode(point: LatLng) { val reverseGeocode = MapboxGeocoding.builder() - .accessToken(Mapbox.getAccessToken()!!) - .query(Point.fromLngLat(point.longitude, point.latitude)) - .geocodingTypes(GeocodingCriteria.TYPE_ADDRESS) - .build() + .accessToken(Mapbox.getAccessToken()!!) + .query(Point.fromLngLat(point.longitude, point.latitude)) + .geocodingTypes(GeocodingCriteria.TYPE_ADDRESS) + .build() reverseGeocode.enqueueCall(object : Callback { override fun onResponse(call: Call, response: Response) { geocode.value = response.body() @@ -153,20 +155,29 @@ class ExampleViewModel(application: Application) : AndroidViewModel(application) } navigation.onDestroy() speechPlayer.onDestroy() - removeLocationEngineListener() + removeLocation() } - private fun addLocationEngineListener() { - locationEngine.addLocationEngineListener(locationEngineListener) + @SuppressLint("MissingPermission") + private fun requestLocation() { + val request = buildEngineRequest() + locationEngine.requestLocationUpdates(request, locationEngineCallback, null) } - private fun removeLocationEngineListener() { - locationEngine.removeLocationEngineListener(locationEngineListener) + private fun removeLocation() { + locationEngine.removeLocationUpdates(locationEngineCallback) } private fun retrieveOfflineVersionFromPreferences(): String { val context = getApplication() return PreferenceManager.getDefaultSharedPreferences(context) - .getString(context.getString(R.string.offline_version_key), "") + .getString(context.getString(R.string.offline_version_key), "") + } + + private fun buildEngineRequest(): LocationEngineRequest { + return LocationEngineRequest.Builder(UPDATE_INTERVAL_IN_MILLISECONDS) + .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY) + .setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS) + .build() } } \ No newline at end of file diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/callout/ExampleCalloutManager.java b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/callout/ExampleCalloutManager.java index 997b32483e1..d1e4a84a8fa 100644 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/callout/ExampleCalloutManager.java +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/callout/ExampleCalloutManager.java @@ -45,8 +45,8 @@ public class ExampleCalloutManager { public ExampleCalloutManager(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; this.geoJsonSource = new GeoJsonSource(SOURCE_ID); - mapboxMap.addSource(geoJsonSource); - mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID).withProperties( + mapboxMap.getStyle().addSource(geoJsonSource); + mapboxMap.getStyle().addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID).withProperties( iconImage(string(get(literal(ExampleCallout.KEY_ID)))), iconAllowOverlap(true), iconIgnorePlacement(true), @@ -135,7 +135,7 @@ private Bitmap generateText(Context context, ExampleCallout callout) { @Override protected void onPostExecute(HashMap bitmapHashMap) { super.onPostExecute(bitmapHashMap); - mapboxMap.addImages(bitmapHashMap); + mapboxMap.getStyle().addImages(bitmapHashMap); } } diff --git a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/navigation/ExampleLocationEngineListener.kt b/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/navigation/ExampleLocationEngineListener.kt deleted file mode 100644 index 152243395e3..00000000000 --- a/app/src/main/java/com/mapbox/services/android/navigation/testapp/example/ui/navigation/ExampleLocationEngineListener.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.mapbox.services.android.navigation.testapp.example.ui.navigation - -import android.annotation.SuppressLint -import android.arch.lifecycle.MutableLiveData -import android.location.Location -import com.mapbox.android.core.location.LocationEngine -import com.mapbox.android.core.location.LocationEngineListener - -class ExampleLocationEngineListener(private val locationEngine: LocationEngine, - private val location: MutableLiveData): LocationEngineListener { - - override fun onLocationChanged(location: Location?) { - this.location.value = location - } - - @SuppressLint("MissingPermission") - override fun onConnected() { - locationEngine.requestLocationUpdates() - - if (locationEngine.lastLocation != null) { - onLocationChanged(locationEngine.lastLocation) - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_component_navigation.xml b/app/src/main/res/layout/activity_component_navigation.xml index bd7f7f0e627..b45a775f525 100644 --- a/app/src/main/res/layout/activity_component_navigation.xml +++ b/app/src/main/res/layout/activity_component_navigation.xml @@ -2,7 +2,6 @@ @@ -14,8 +13,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - mapbox:mapbox_styleUrl="mapbox://styles/designevokes/cjksybfj600xj2roja7iwnygu"/> + app:layout_constraintTop_toTopOf="parent"/> diff --git a/app/src/main/res/layout/activity_mock_navigation.xml b/app/src/main/res/layout/activity_mock_navigation.xml index d81d5ff8edf..e54b36cd1d8 100644 --- a/app/src/main/res/layout/activity_mock_navigation.xml +++ b/app/src/main/res/layout/activity_mock_navigation.xml @@ -14,7 +14,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:mapbox_cameraZoom="14" - app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" app:mapbox_uiAttribution="false"/>