Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import android.support.test.rule.ActivityTestRule
import android.support.test.rule.GrantPermissionRule
import android.support.test.rule.GrantPermissionRule.grant
import android.support.test.runner.AndroidJUnit4
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.constants.Style
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.*
import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode
Expand All @@ -30,6 +32,7 @@ import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.Matchers.equalTo
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Rule
Expand All @@ -56,6 +59,7 @@ class LocationLayerTest {
val initLocation = Location("test")
initLocation.latitude = 15.0
initLocation.longitude = 17.0
initLocation.accuracy = 2000f
initLocation
}

Expand Down Expand Up @@ -259,6 +263,62 @@ class LocationLayerTest {
onView(withId(R.id.content)).check(matches(isDisplayed()))
}

@Test
fun accuracy_visibleWithNewLocation() {
val pluginAction = object : GenericPluginAction.OnPerformGenericPluginAction<LocationLayerPlugin> {
override fun onGenericPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap,
uiController: UiController, context: Context) {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0))
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
plugin.forceLocationUpdate(location)
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)

assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/,
mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
.getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f)
}
}
executePluginTest(pluginAction)
}

@Test
fun accuracy_visibleWhenCameraEased() {
val pluginAction = object : GenericPluginAction.OnPerformGenericPluginAction<LocationLayerPlugin> {
override fun onGenericPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap,
uiController: UiController, context: Context) {
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
plugin.forceLocationUpdate(location)
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0), 300)
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300)

assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/,
mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
.getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f)
}
}
executePluginTest(pluginAction)
}

@Test
fun accuracy_visibleWhenCameraMoved() {
val pluginAction = object : GenericPluginAction.OnPerformGenericPluginAction<LocationLayerPlugin> {
override fun onGenericPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap,
uiController: UiController, context: Context) {
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
plugin.forceLocationUpdate(location)
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0))
uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300)

assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/,
mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
.getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f)
}
}
executePluginTest(pluginAction)
}

@After
fun afterTest() {
Timber.e("@After: unregister idle resource")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.PROPERTY_SHADOW_ICON_OFFSET;
import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.SHADOW_ICON;
import static com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.SHADOW_LAYER;
import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.calculateZoomLevelRadius;
import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.generateShadow;
import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.getBitmapFromDrawable;
import static com.mapbox.mapboxsdk.plugins.locationlayer.Utils.getDrawable;
Expand Down Expand Up @@ -263,20 +264,11 @@ private void setBearingProperty(String propertyId, float bearing) {

void updateAccuracyRadius(Location location) {
if (renderMode == RenderMode.COMPASS || renderMode == RenderMode.NORMAL) {
locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, calculateZoomLevelRadius(location));
locationFeature.addNumberProperty(PROPERTY_ACCURACY_RADIUS, calculateZoomLevelRadius(mapboxMap, location));
refreshSource();
}
}

private float calculateZoomLevelRadius(Location location) {
if (location == null) {
return 0;
}
double metersPerPixel = mapboxMap.getProjection().getMetersPerPixelAtLatitude(
location.getLatitude());
return (float) (location.getAccuracy() * (1 / metersPerPixel));
}

void updateForegroundOffset(double tilt) {
JsonArray foregroundJsonArray = new JsonArray();
foregroundJsonArray.add(0f);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapView.OnMapChangedListener;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener;
import com.mapbox.mapboxsdk.plugins.locationlayer.modes.CameraMode;
Expand Down Expand Up @@ -72,6 +73,11 @@ public final class LocationLayerPlugin implements LifecycleObserver {

private LocationLayerAnimator locationLayerAnimator;

/**
* Holds last location which is being returned in the {@link #getLastKnownLocation()}
* when there is no {@link #locationEngine} set or when the last location returned by the engine is null.
*/
private Location lastLocation;
private CameraPosition lastCameraPosition;

/**
Expand Down Expand Up @@ -358,7 +364,11 @@ public LocationEngine getLocationEngine() {
@Nullable
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public Location getLastKnownLocation() {
return locationEngine != null ? locationEngine.getLastLocation() : null;
Location location = locationEngine != null ? locationEngine.getLastLocation() : null;
if (location == null) {
location = lastLocation;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LukasPaczos Per javadoc above - here we are trying to get the last known location from the location engine and if nothing is found, using lastLocation which could also possibly be null? Just clarifying here, I think it makes sense to add the extra check in case a developer was forcing Location updates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, lastLocation can also be null if no updates have been pushed to the plugin yet. This is our last resort if locationEngine is null or fails to provide non-null location, like a scenario when we are only forcing location updates.

The idea here is, that LocationEngine can be in a position to provide last location (or just more recent location) even if no location updates have been pushed to the plugin itself.

}
return location;
}

/**
Expand Down Expand Up @@ -508,6 +518,7 @@ void onLocationLayerStart() {
}
if (mapboxMap != null) {
mapboxMap.addOnCameraMoveListener(onCameraMoveListener);
mapboxMap.addOnCameraIdleListener(onCameraIdleListener);
}
if (options.enableStaleState()) {
staleStateManager.onStart();
Expand All @@ -530,6 +541,7 @@ void onLocationLayerStop() {
}
if (mapboxMap != null) {
mapboxMap.removeOnCameraMoveListener(onCameraMoveListener);
mapboxMap.removeOnCameraIdleListener(onCameraIdleListener);
}
}

Expand Down Expand Up @@ -593,14 +605,19 @@ private void updateMapWithOptions(final LocationLayerOptions options) {
* @since 0.1.0
*/
private void updateLocation(final Location location) {
if (location == null || !isLocationLayerStarted) {
if (location == null) {
return;
} else if (!isLocationLayerStarted) {
lastLocation = location;
return;
}

staleStateManager.updateLatestLocationTime();
CameraPosition currentCameraPosition = mapboxMap.getCameraPosition();
boolean isGpsNorth = getCameraMode() == CameraMode.TRACKING_GPS_NORTH;
locationLayerAnimator.feedNewLocation(location, currentCameraPosition, isGpsNorth);
locationLayer.updateAccuracyRadius(location);
lastLocation = location;
}

private void updateCompassHeading(float heading) {
Expand Down Expand Up @@ -646,13 +663,19 @@ private void updateLayerOffsets(boolean forceUpdate) {
}

private OnCameraMoveListener onCameraMoveListener = new OnCameraMoveListener() {

@Override
public void onCameraMove() {
updateLayerOffsets(false);
}
};

private OnCameraIdleListener onCameraIdleListener = new OnCameraIdleListener() {
@Override
public void onCameraIdle() {
updateLayerOffsets(false);
}
};

private OnMapClickListener onMapClickListener = new OnMapClickListener() {
@Override
public void onMapClick(@NonNull LatLng point) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;

import com.mapbox.mapboxsdk.maps.MapboxMap;

public final class Utils {

private Utils() {
Expand Down Expand Up @@ -77,6 +80,15 @@ static Drawable getDrawable(@NonNull Context context, @DrawableRes int drawableR
return drawable;
}

static float calculateZoomLevelRadius(MapboxMap mapboxMap, Location location) {
if (location == null) {
return 0;
}
double metersPerPixel = mapboxMap.getProjection().getMetersPerPixelAtLatitude(
location.getLatitude());
return (float) (location.getAccuracy() * (1 / metersPerPixel));
}

/**
* Casts the value to an even integer.
*/
Expand Down