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 new file mode 100644 index 00000000000..eeec7bbf064 --- /dev/null +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/ForwardingLocationCallback.java @@ -0,0 +1,28 @@ +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 new file mode 100644 index 00000000000..30188bc0114 --- /dev/null +++ b/app/src/main/java/com/mapbox/services/android/navigation/testapp/activity/location/FusedLocationEngine.java @@ -0,0 +1,137 @@ +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 8fa35f72d5a..fb5af6ed6d8 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 @@ -20,7 +20,6 @@ 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.LocationEngineProvider; import com.mapbox.api.directions.v5.models.DirectionsResponse; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.geojson.Point; @@ -33,6 +32,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.services.android.navigation.testapp.R; +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.instruction.InstructionView; import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap; @@ -326,11 +326,11 @@ private void initializeSpeechPlayer() { } private void initializeLocationEngine() { - LocationEngineProvider locationEngineProvider = new LocationEngineProvider(this); - locationEngine = locationEngineProvider.obtainBestLocationEngineAvailable(); + locationEngine = new FusedLocationEngine(getApplicationContext()); locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); locationEngine.addLocationEngineListener(this); - locationEngine.setFastestInterval(ONE_SECOND_INTERVAL); + locationEngine.setInterval(ONE_SECOND_INTERVAL); + locationEngine.setFastestInterval(500); locationEngine.activate(); showSnackbar(SEARCHING_FOR_GPS_MESSAGE, BaseTransientBottomBar.LENGTH_SHORT); } diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/MapboxNavigator.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/MapboxNavigator.java index c061cbed9d5..deabd5f153d 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/MapboxNavigator.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/MapboxNavigator.java @@ -60,8 +60,8 @@ synchronized void toggleHistory(boolean isEnabled) { } FixLocation buildFixLocationFromLocation(Location location) { + Date time = new Date(); Point rawPoint = Point.fromLngLat(location.getLongitude(), location.getLatitude()); - Date time = new Date(location.getTime()); Float speed = checkFor(location.getSpeed()); Float bearing = checkFor(location.getBearing()); Float altitude = checkFor((float) location.getAltitude());