[android] refactor LocationComponent to utilize LocationEngineRequest

This commit is contained in:
Łukasz Paczos
2018-11-12 17:11:51 +01:00
committed by Łukasz Paczos
parent 2c70f4b6dc
commit 216b0d8a93
10 changed files with 420 additions and 223 deletions

View File

@@ -9,6 +9,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresPermission;
import android.support.annotation.StyleRes;
import android.support.annotation.VisibleForTesting;
import android.view.WindowManager;
import com.mapbox.android.core.location.LocationEngine;
@@ -28,13 +29,13 @@ import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener;
import java.lang.ref.WeakReference;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_FASTEST_INTERVAL_MILLIS;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_INTERVAL_MILLIS;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION;
import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION;
@@ -60,14 +61,23 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_T
* <p>
* Using this component requires you to request permission beforehand manually or using
* {@link com.mapbox.android.core.permissions.PermissionsManager}. Either
* {@code ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permissions can be requested and
* this plugin work as expected.
* {@code ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permissions can be requested for
* this component to work as expected.
* <p>
* This component offers a default, built-in {@link LocationEngine} with some of the activation methods.
* This engine will be obtained by {@link LocationEngineProvider#getBestLocationEngine(Context, boolean)} which defaults
* to the {@link com.mapbox.android.core.location.MapboxFusedLocationEngineImpl}. If you'd like to utilize Google Play Services
* to the {@link com.mapbox.android.core.location.MapboxFusedLocationEngineImpl}. If you'd like to utilize Google
* Play Services
* for more precise location updates, simply add the Google Play Location Services dependency in your build script.
* This will make the default engine the {@link com.mapbox.android.core.location.GoogleLocationEngineImpl} instead.
* After a custom engine is passed to the component, or the built-in is initialized,
* the location updates are going to be requested with the {@link LocationEngineRequest}, either a default one,
* or the one passed during the activation.
* When using any engine, requesting/removing the location updates is going to be managed internally.
* <p>
* You can also push location updates to the component without any internal engine management.
* To achieve that, use {@link #activateLocationComponent(Context, boolean)} with false.
* No engine is going to be initialized and you can push location updates with {@link #forceLocationUpdate(Location)}.
* <p>
* For location puck animation purposes, like navigation,
* we recommend limiting the maximum zoom level of the map for the best user experience.
@@ -76,17 +86,26 @@ import static com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_T
*/
public final class LocationComponent {
private static final String TAG = "Mbgl-LocationComponent";
private static final long DEFAULT_INTERVAL_MILLIS = 1000;
private static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000;
@NonNull
private final MapboxMap mapboxMap;
private LocationComponentOptions options;
@NonNull
private InternalLocationEngineProvider internalLocationEngineProvider = new InternalLocationEngineProvider();
@Nullable
private LocationEngine locationEngine;
@Nullable
@NonNull
private LocationEngineRequest locationEngineRequest =
new LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS)
.setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build();
private LocationEngineCallback<LocationEngineResult> currentLocationEngineListener
= new CurrentLocationEngineCallback(this);
private LocationEngineCallback<LocationEngineResult> lastLocationEngineListener
= new LastLocationEngineCallback(this);
private CompassEngine compassEngine;
private boolean usingInternalLocationEngine;
private LocationLayerController locationLayerController;
private LocationCameraController locationCameraController;
@@ -144,6 +163,28 @@ public final class LocationComponent {
this.mapboxMap = mapboxMap;
}
@VisibleForTesting
LocationComponent(@NonNull MapboxMap mapboxMap,
@NonNull LocationEngineCallback<LocationEngineResult> currentlistener,
@NonNull LocationEngineCallback<LocationEngineResult> lastListener,
@NonNull LocationLayerController locationLayerController,
@NonNull LocationCameraController locationCameraController,
@NonNull LocationAnimatorCoordinator locationAnimatorCoordinator,
@NonNull StaleStateManager staleStateManager,
@NonNull CompassEngine compassEngine,
@NonNull InternalLocationEngineProvider internalLocationEngineProvider) {
this.mapboxMap = mapboxMap;
this.currentLocationEngineListener = currentlistener;
this.lastLocationEngineListener = lastListener;
this.locationLayerController = locationLayerController;
this.locationCameraController = locationCameraController;
this.locationAnimatorCoordinator = locationAnimatorCoordinator;
this.staleStateManager = staleStateManager;
this.compassEngine = compassEngine;
this.internalLocationEngineProvider = internalLocationEngineProvider;
isInitialized = true;
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
@@ -154,8 +195,8 @@ public final class LocationComponent {
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context) {
activateLocationComponent(context, LocationComponentOptions.createFromAttributes(context, R.style
.mapbox_LocationComponent));
activateLocationComponent(context,
LocationComponentOptions.createFromAttributes(context, R.style.mapbox_LocationComponent));
}
/**
@@ -175,6 +216,26 @@ public final class LocationComponent {
}
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
*
* @param context the context
* @param useDefaultLocationEngine true if you want to initialize and use the built-in location engine or false if
* there should be no location engine initialized
* @param locationEngineRequest the location request
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, boolean useDefaultLocationEngine,
@NonNull LocationEngineRequest locationEngineRequest) {
setLocationEngineRequest(locationEngineRequest);
if (useDefaultLocationEngine) {
activateLocationComponent(context, R.style.mapbox_LocationComponent);
} else {
activateLocationComponent(context, null, R.style.mapbox_LocationComponent);
}
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
@@ -214,22 +275,53 @@ public final class LocationComponent {
* @param locationEngine the engine, or null if you'd like to only force location updates
* @param styleRes the LocationComponent style res
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, @Nullable LocationEngine locationEngine,
@StyleRes int styleRes) {
activateLocationComponent(context, locationEngine,
LocationComponentOptions.createFromAttributes(context, styleRes));
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
*
* @param context the context
* @param locationEngine the engine, or null if you'd like to only force location updates
* @param locationEngineRequest the location request
* @param styleRes the LocationComponent style res
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, @Nullable LocationEngine locationEngine,
@NonNull LocationEngineRequest locationEngineRequest, @StyleRes int styleRes) {
activateLocationComponent(context, locationEngine, locationEngineRequest,
LocationComponentOptions.createFromAttributes(context, styleRes));
}
/**
* This method will show the location icon and enable the camera tracking the location.
*
* @param context the context
* @param locationEngine the engine
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, @NonNull LocationEngine locationEngine) {
activateLocationComponent(context, locationEngine, R.style.mapbox_LocationComponent);
}
/**
* This method will show the location icon and enable the camera tracking the location.
*
* @param context the context
* @param locationEngine the engine
* @param locationEngineRequest the location request
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, @NonNull LocationEngine locationEngine,
@NonNull LocationEngineRequest locationEngineRequest) {
activateLocationComponent(context, locationEngine, locationEngineRequest, R.style.mapbox_LocationComponent);
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
@@ -237,6 +329,7 @@ public final class LocationComponent {
* @param locationEngine the engine, or null if you'd like to only force location updates
* @param options the options
*/
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void activateLocationComponent(@NonNull Context context, @Nullable LocationEngine locationEngine,
@NonNull LocationComponentOptions options) {
initialize(context, options);
@@ -244,6 +337,24 @@ public final class LocationComponent {
applyStyle(options);
}
/**
* This method initializes the component and needs to be called before any other operations are performed.
* Afterwards, you can manage component's visibility by {@link #setLocationComponentEnabled(boolean)}.
*
* @param context the context
* @param locationEngine the engine, or null if you'd like to only force location updates
* @param locationEngineRequest the location request
* @param options the options
*/
public void activateLocationComponent(@NonNull Context context, @Nullable LocationEngine locationEngine,
@NonNull LocationEngineRequest locationEngineRequest,
@NonNull LocationComponentOptions options) {
initialize(context, options);
setLocationEngineRequest(locationEngineRequest);
setLocationEngine(locationEngine);
applyStyle(options);
}
/**
* Manage component's visibility after activation.
*
@@ -491,22 +602,45 @@ public final class LocationComponent {
*
* @param locationEngine a {@link LocationEngine} this component should use to handle updates
*/
@SuppressLint("MissingPermission")
public void setLocationEngine(@Nullable LocationEngine locationEngine) {
if (this.locationEngine != null) {
// If internal location engines being used, extra steps need to be taken to deconstruct the
// instance.
if (usingInternalLocationEngine) {
usingInternalLocationEngine = false;
}
this.locationEngine.removeLocationUpdates(locationEngineListener);
this.locationEngine.removeLocationUpdates(currentLocationEngineListener);
this.locationEngine = null;
}
if (locationEngine != null) {
this.locationEngine = locationEngine;
if (isLayerReady && isEnabled) {
setLastLocation();
locationEngine.requestLocationUpdates(
locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper());
}
}
}
/**
* Set the location request that's going to be used when requesting location updates.
*
* @param locationEngineRequest the location request
*/
public void setLocationEngineRequest(@NonNull LocationEngineRequest locationEngineRequest) {
this.locationEngineRequest = locationEngineRequest;
// reset internal LocationEngine ref to re-request location updates if needed
setLocationEngine(locationEngine);
}
/**
* Get the location request that's going to be used when requesting location updates.
*/
@NonNull
public LocationEngineRequest getLocationEngineRequest() {
return locationEngineRequest;
}
/**
* Returns the current {@link LocationEngine} being used for updating the user location.
*
@@ -546,31 +680,7 @@ public final class LocationComponent {
@Nullable
@RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public Location getLastKnownLocation() {
if (locationEngine == null) {
return null;
}
// TODO: decide if we want to change signature of this method, for now make it work as is
final AtomicReference<LocationEngineResult> resultRef = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
locationEngine.getLastLocation(new LocationEngineCallback<LocationEngineResult>() {
@Override
public void onSuccess(LocationEngineResult result) {
resultRef.set(result);
latch.countDown();
}
@Override
public void onFailure(@NonNull Exception exception) {
// TODO: log exception
}
});
try {
latch.await(2, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
LocationEngineResult result = resultRef.get();
return result != null ? result.getLastLocation() : null;
return lastLocation;
}
/**
@@ -750,13 +860,11 @@ public final class LocationComponent {
if (isEnabled) {
if (locationEngine != null) {
if (usingInternalLocationEngine) {
try {
locationEngine.requestLocationUpdates(getLocationRequst(DEFAULT_INTERVAL_MILLIS),
locationEngineListener, Looper.getMainLooper());
} catch (SecurityException se) {
se.printStackTrace();
}
try {
locationEngine.requestLocationUpdates(
locationEngineRequest, currentLocationEngineListener, Looper.getMainLooper());
} catch (SecurityException se) {
Logger.e(TAG, "Unable to request location updates", se);
}
}
setCameraMode(locationCameraController.getCameraMode());
@@ -776,9 +884,7 @@ public final class LocationComponent {
compassEngine.onStop();
locationAnimatorCoordinator.cancelAllAnimations();
if (locationEngine != null) {
if (usingInternalLocationEngine) {
locationEngine.removeLocationUpdates(locationEngineListener);
}
locationEngine.removeLocationUpdates(currentLocationEngineListener);
}
mapboxMap.removeOnCameraMoveListener(onCameraMoveListener);
mapboxMap.removeOnCameraIdleListener(onCameraIdleListener);
@@ -823,17 +929,9 @@ public final class LocationComponent {
private void initializeLocationEngine(@NonNull Context context) {
if (this.locationEngine != null) {
this.locationEngine.removeLocationUpdates(locationEngineListener);
this.locationEngine.removeLocationUpdates(currentLocationEngineListener);
}
usingInternalLocationEngine = true;
locationEngine = LocationEngineProvider.getBestLocationEngine(context, false);
}
private static LocationEngineRequest getLocationRequst(long interval) {
return new LocationEngineRequest.Builder(interval)
.setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build();
locationEngine = internalLocationEngineProvider.getBestLocationEngine(context, false);
}
private void enableLocationComponent() {
@@ -846,10 +944,13 @@ public final class LocationComponent {
onLocationLayerStop();
}
private void updateMapWithOptions(final LocationComponentOptions options) {
mapboxMap.setPadding(
options.padding()[0], options.padding()[1], options.padding()[2], options.padding()[3]
);
private void updateMapWithOptions(@NonNull LocationComponentOptions options) {
int[] padding = options.padding();
if (padding != null) {
mapboxMap.setPadding(
padding[0], padding[1], padding[2], padding[3]
);
}
}
/**
@@ -894,7 +995,11 @@ public final class LocationComponent {
*/
@SuppressLint("MissingPermission")
private void setLastLocation() {
updateLocation(getLastKnownLocation(), true);
if (locationEngine != null) {
locationEngine.getLastLocation(lastLocationEngineListener);
} else {
updateLocation(getLastKnownLocation(), true);
}
}
private void setLastCompassHeading() {
@@ -1005,22 +1110,49 @@ public final class LocationComponent {
}
};
@NonNull
private LocationEngineCallback<LocationEngineResult> locationEngineListener =
new LocationEngineCallback<LocationEngineResult>() {
@VisibleForTesting
static final class CurrentLocationEngineCallback implements LocationEngineCallback<LocationEngineResult> {
private final WeakReference<LocationComponent> componentWeakReference;
CurrentLocationEngineCallback(LocationComponent component) {
this.componentWeakReference = new WeakReference<>(component);
}
@Override
public void onSuccess(LocationEngineResult result) {
Location location = result.getLastLocation();
if (location != null) {
updateLocation(location, false);
LocationComponent component = componentWeakReference.get();
if (component != null) {
component.updateLocation(result.getLastLocation(), false);
}
}
@Override
public void onFailure(@NonNull Exception exception) {
// TODO: handle error
Logger.e(TAG, "Failed to obtain location update", exception);
}
};
}
@VisibleForTesting
static final class LastLocationEngineCallback implements LocationEngineCallback<LocationEngineResult> {
private final WeakReference<LocationComponent> componentWeakReference;
LastLocationEngineCallback(LocationComponent component) {
this.componentWeakReference = new WeakReference<>(component);
}
@Override
public void onSuccess(LocationEngineResult result) {
LocationComponent component = componentWeakReference.get();
if (component != null) {
component.updateLocation(result.getLastLocation(), true);
}
}
@Override
public void onFailure(@NonNull Exception exception) {
Logger.e(TAG, "Failed to obtain last location update", exception);
}
}
@NonNull
private OnCameraTrackingChangedListener cameraTrackingChangedListener = new OnCameraTrackingChangedListener() {
@@ -1040,4 +1172,10 @@ public final class LocationComponent {
}
}
};
static class InternalLocationEngineProvider {
LocationEngine getBestLocationEngine(@NonNull Context context, boolean background) {
return LocationEngineProvider.getBestLocationEngine(context, background);
}
}
}

View File

@@ -26,6 +26,12 @@ final class LocationComponentConstants {
// Threshold value to perform immediate camera/layer position update.
static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 500_000;
// Default interval between location updates
static final long DEFAULT_INTERVAL_MILLIS = 1000;
// Default fastest acceptable interval between location updates
static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000;
// Sources
static final String LOCATION_SOURCE = "mapbox-location-source";
static final String PROPERTY_GPS_BEARING = "mapbox-property-gps-bearing";

View File

@@ -187,7 +187,7 @@ public class LocationComponentOptions implements Parcelable {
* @return a new {@link LocationComponentOptions} object with the settings you defined in your style
* resource
*/
@Nullable
@NonNull
public static LocationComponentOptions createFromAttributes(@NonNull Context context,
@StyleRes int styleRes) {

View File

@@ -0,0 +1,140 @@
package com.mapbox.mapboxsdk.location
import android.content.Context
import android.content.res.Resources
import android.content.res.TypedArray
import android.os.Looper
import com.mapbox.android.core.location.LocationEngine
import com.mapbox.android.core.location.LocationEngineRequest
import com.mapbox.mapboxsdk.R
import com.mapbox.mapboxsdk.maps.MapboxMap
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class LocationComponentTest {
private lateinit var locationComponent: LocationComponent
@Mock
private lateinit var locationComponentOptions: LocationComponentOptions
@Mock
private lateinit var mapboxMap: MapboxMap
@Mock
private lateinit var context: Context
@Mock
private lateinit var locationEngine: LocationEngine
@Mock
private lateinit var locationEngineRequest: LocationEngineRequest
@Mock
private lateinit var currentListener: LocationComponent.CurrentLocationEngineCallback
@Mock
private lateinit var lastListener: LocationComponent.LastLocationEngineCallback
@Mock
private lateinit var compassEngine: CompassEngine
@Mock
private lateinit var locationLayerController: LocationLayerController
@Mock
private lateinit var locationCameraController: LocationCameraController
@Mock
private lateinit var locationAnimatorCoordinator: LocationAnimatorCoordinator
@Mock
private lateinit var staleStateManager: StaleStateManager
@Mock
private lateinit var locationEngineProvider: LocationComponent.InternalLocationEngineProvider
@Before
fun before() {
MockitoAnnotations.initMocks(this)
locationComponent = LocationComponent(mapboxMap, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider)
doReturn(locationEngine).`when`(locationEngineProvider).getBestLocationEngine(context, false)
}
@Test
fun activateWithRequestTest() {
locationComponent.activateLocationComponent(context, locationEngine, locationEngineRequest, locationComponentOptions)
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
doReturn(mock(TypedArray::class.java)).`when`(context)
.obtainStyledAttributes(R.style.mapbox_LocationComponent, R.styleable.mapbox_LocationComponent)
val resources = mock(Resources::class.java)
doReturn(resources).`when`(context).resources
doReturn(0f).`when`(resources)
.getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold)
doReturn(0f).`when`(resources)
.getDimension(R.dimen.mapbox_locationComponentTrackingMultiFingerMoveThreshold)
locationComponent.activateLocationComponent(context, true, locationEngineRequest)
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
}
@Test
fun locationUpdatesWhenEnabledDisableTest() {
locationComponent.activateLocationComponent(context, locationEngine, locationEngineRequest, locationComponentOptions)
verify(locationEngine, times(0)).removeLocationUpdates(currentListener)
verify(locationEngine, times(0)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
locationComponent.onStart()
verify(locationEngine, times(0)).removeLocationUpdates(currentListener)
verify(locationEngine, times(0)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
locationComponent.isLocationComponentEnabled = true
verify(locationEngine).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
locationComponent.isLocationComponentEnabled = false
verify(locationEngine).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
verify(locationEngine).removeLocationUpdates(currentListener)
}
@Test
fun locationUpdatesWhenStartedStoppedTest() {
locationComponent.activateLocationComponent(context, locationEngine, locationEngineRequest, locationComponentOptions)
locationComponent.onStart()
locationComponent.isLocationComponentEnabled = true
locationComponent.onStop()
verify(locationEngine).removeLocationUpdates(currentListener)
locationComponent.onStart()
verify(locationEngine, times(2)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
}
@Test
fun locationUpdatesWhenNewRequestTest() {
locationComponent.activateLocationComponent(context, locationEngine, locationEngineRequest, locationComponentOptions)
locationComponent.onStart()
locationComponent.isLocationComponentEnabled = true
val newRequest = mock(LocationEngineRequest::class.java)
locationComponent.locationEngineRequest = newRequest
verify(locationEngine).removeLocationUpdates(currentListener)
verify(locationEngine).requestLocationUpdates(eq(newRequest), eq(currentListener), any(Looper::class.java))
}
@Test
fun lastLocationUpdateOnStartTest() {
locationComponent.activateLocationComponent(context, locationEngine, locationEngineRequest, locationComponentOptions)
locationComponent.onStart()
locationComponent.isLocationComponentEnabled = true
verify(locationEngine).getLastLocation(lastListener)
}
}

View File

@@ -65,7 +65,6 @@ dependencies {
implementation dependenciesList.supportDesign
implementation dependenciesList.supportConstraintLayout
// implementation dependenciesList.lost
implementation dependenciesList.gmsLocation
implementation dependenciesList.timber
debugImplementation dependenciesList.leakCanaryDebug

View File

@@ -105,8 +105,7 @@ class LocationFragmentActivity : AppCompatActivity() {
mapView.getMapAsync {
mapboxMap = it
component = mapboxMap.locationComponent
component?.activateLocationComponent(activity,
LocationEngineProvider.getBestLocationEngine(activity, false))
component?.activateLocationComponent(activity)
component?.isLocationComponentEnabled = true
component?.locationEngine?.getLastLocation(this)
}

View File

@@ -4,45 +4,36 @@ import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.ListPopupWindow;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Toast;
import com.mapbox.android.core.location.LocationEngine;
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.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;
import com.mapbox.mapboxsdk.location.OnLocationClickListener;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.List;
public class LocationModesActivity extends AppCompatActivity implements OnMapReadyCallback,
OnLocationClickListener, OnCameraTrackingChangedListener {
private static final long DEFAULT_INTERVAL_MILLIS = 1000;
private static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000;
OnLocationClickListener, OnCameraTrackingChangedListener {
private MapView mapView;
private Button locationModeBtn;
@@ -51,7 +42,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
private PermissionsManager permissionsManager;
private LocationComponent locationComponent;
private LocationEngine locationEngine;
private MapboxMap mapboxMap;
private boolean customStyle;
@@ -67,8 +57,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
private Location lastLocation;
private LocationEngineCallback<LocationEngineResult> locationEngineCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -77,25 +65,19 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
mapView = findViewById(R.id.mapView);
locationModeBtn = findViewById(R.id.button_location_mode);
locationModeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (locationComponent == null) {
return;
}
showModeListDialog();
locationModeBtn.setOnClickListener(v -> {
if (locationComponent == null) {
return;
}
showModeListDialog();
});
locationTrackingBtn = findViewById(R.id.button_location_tracking);
locationTrackingBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (locationComponent == null) {
return;
}
showTrackingListDialog();
locationTrackingBtn.setOnClickListener(v -> {
if (locationComponent == null) {
return;
}
showTrackingListDialog();
});
@@ -141,20 +123,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext(),
false);
locationEngineCallback = new LocationEngineCallback<LocationEngineResult>() {
@Override
public void onSuccess(LocationEngineResult result) {
// noop
}
@Override
public void onFailure(@NonNull Exception exception) {
// noop
}
};
int[] padding;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
padding = new int[] {0, 750, 0, 0};
@@ -168,7 +136,13 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
.build();
locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(this, locationEngine, options);
locationComponent.activateLocationComponent(this, true,
new LocationEngineRequest.Builder(750)
.setFastestInterval(750)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build()
);
locationComponent.applyStyle(options);
locationComponent.setLocationComponentEnabled(true);
locationComponent.addOnLocationClickListener(this);
locationComponent.addOnCameraTrackingChangedListener(this);
@@ -248,14 +222,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
protected void onStart() {
super.onStart();
mapView.onStart();
if (locationEngine != null) {
try {
locationEngine.requestLocationUpdates(getLocationRequst(DEFAULT_INTERVAL_MILLIS),
locationEngineCallback, Looper.getMainLooper());
} catch (SecurityException se) {
se.printStackTrace();
}
}
}
@Override
@@ -274,9 +240,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
protected void onStop() {
super.onStop();
mapView.onStop();
if (locationEngine != null) {
locationEngine.removeLocationUpdates(locationEngineCallback);
}
}
@SuppressLint("MissingPermission")
@@ -303,13 +266,6 @@ public class LocationModesActivity extends AppCompatActivity implements OnMapRea
mapView.onLowMemory();
}
private static LocationEngineRequest getLocationRequst(long interval) {
return new LocationEngineRequest.Builder(interval)
.setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build();
}
@Override
public void onLocationComponentClick() {
Toast.makeText(this, "OnLocationComponentClick", Toast.LENGTH_LONG).show();

View File

@@ -1,38 +1,28 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.location.Location;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.mapbox.android.core.location.LocationEngine;
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.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.List;
import timber.log.Timber;
public class ManualLocationUpdatesActivity extends AppCompatActivity implements OnMapReadyCallback,
LocationEngineCallback<LocationEngineResult> {
private static final long DEFAULT_INTERVAL_MILLIS = 1000;
private static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000;
public class ManualLocationUpdatesActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private LocationComponent locationComponent;
@@ -44,43 +34,38 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_manual_update);
locationEngine = LocationEngineProvider.getBestLocationEngine(this, false);
FloatingActionButton fabManualUpdate = findViewById(R.id.fabManualLocationChange);
fabManualUpdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (locationComponent != null && locationComponent.getLocationEngine() == null) {
locationComponent.forceLocationUpdate(
Utils.getRandomLocation(LatLngBounds.from(60, 25, 40, -5)));
}
fabManualUpdate.setOnClickListener(v -> {
if (locationComponent != null && locationComponent.getLocationEngine() == null) {
locationComponent.forceLocationUpdate(
Utils.getRandomLocation(LatLngBounds.from(60, 25, 40, -5)));
}
});
fabManualUpdate.setEnabled(false);
FloatingActionButton fabToggle = findViewById(R.id.fabToggleManualLocation);
fabToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (locationComponent != null) {
locationComponent.setLocationEngine(locationComponent.getLocationEngine() == null ? locationEngine :
null);
fabToggle.setOnClickListener(v -> {
if (locationComponent != null) {
locationComponent.setLocationEngine(locationComponent.getLocationEngine() == null ? locationEngine : null);
if (locationComponent.getLocationEngine() == null) {
fabToggle.setImageResource(R.drawable.ic_layers_clear);
fabManualUpdate.setEnabled(true);
fabManualUpdate.setAlpha(1f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine disable, use manual updates",
Toast.LENGTH_SHORT).show();
} else {
fabToggle.setImageResource(R.drawable.ic_layers);
fabManualUpdate.setEnabled(false);
fabManualUpdate.setAlpha(0.5f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine enabled",
Toast.LENGTH_SHORT).show();
}
if (locationComponent.getLocationEngine() == null) {
fabToggle.setImageResource(R.drawable.ic_layers_clear);
fabManualUpdate.setEnabled(true);
fabManualUpdate.setAlpha(1f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine disabled, use manual updates",
Toast.LENGTH_SHORT).show();
} else {
fabToggle.setImageResource(R.drawable.ic_layers);
fabManualUpdate.setEnabled(false);
fabManualUpdate.setAlpha(0.5f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine enabled",
Toast.LENGTH_SHORT).show();
}
}
});
@@ -119,35 +104,25 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@SuppressLint("MissingPermission")
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
locationEngine = LocationEngineProvider.getBestLocationEngine(getApplicationContext(),
false);
locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(this, locationEngine);
locationComponent.activateLocationComponent(
this,
locationEngine,
new LocationEngineRequest.Builder(500)
.setFastestInterval(500)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build());
locationComponent.setLocationComponentEnabled(true);
locationComponent.setRenderMode(RenderMode.COMPASS);
}
private static LocationEngineRequest getLocationRequst(long interval) {
return new LocationEngineRequest.Builder(interval)
.setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
if (locationEngine != null) {
try {
locationEngine.requestLocationUpdates(getLocationRequst(DEFAULT_INTERVAL_MILLIS),
this, Looper.getMainLooper());
} catch (SecurityException se) {
se.printStackTrace();
}
}
}
@Override
@@ -166,9 +141,6 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements
protected void onStop() {
super.onStop();
mapView.onStop();
if (locationEngine != null) {
locationEngine.removeLocationUpdates(this);
}
}
@Override
@@ -188,17 +160,4 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onSuccess(LocationEngineResult result) {
Location location = result.getLastLocation();
if (location != null) {
Timber.d("Location change occurred: %s", location.toString());
}
}
@Override
public void onFailure(@NonNull Exception exception) {
Timber.d("Location engine error occurred: %s", exception.getMessage());
}
}

View File

@@ -18,7 +18,7 @@ allprojects {
google()
jcenter()
// Snapshot repository
//maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
}
}

View File

@@ -9,7 +9,7 @@ ext {
versions = [
mapboxServices : '4.1.0',
mapboxTelemetry : '4.0.0',
mapboxTelemetry : '4.1.0-SNAPSHOT',
mapboxGestures : '0.3.0',
supportLib : '27.1.1',
constraintLayout: '1.1.2',