@@ -6,12 +6,16 @@ MapLibre welcomes participation and contributions from everyone. Please read [`C
|
||||
|
||||
* Add your pull request...
|
||||
|
||||
## 10.0.0 - February 10, 2023
|
||||
## 10.0.0 - February 14, 2023
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Breaking: Changed resourcePrefix to `maplibre_` from `mapbox_` [647](https://github.com/maplibre/maplibre-gl-native/pull/647) and renamed resources accordingly. Note that this is a breaking change since the names of public resources were renamed as well. Replaced Mapbox logo with MapLibre logo.
|
||||
* GMS location: Replace new LocationRequest() with LocationRequest.Builder, and LocationRequest.PRIORITY_X with Priority.PRIORITY_X ([620](https://github.com/maplibre/maplibre-gl-native/pull/620))
|
||||
* Breaking: Changed resourcePrefix to `maplibre_` from `mapbox_` ([#647](https://github.com/maplibre/maplibre-gl-native/pull/647)) and renamed resources accordingly. Note that this is a breaking change since the names of public resources were renamed as well. Replaced Mapbox logo with MapLibre logo.
|
||||
* Breaking: several deprecated overloads of `LocationComponent.activateLocationComponent` were removed. Use `LocationComponentActivationOptions.Builder` instead.
|
||||
* Breaking: the `LocationEngine` implemented with Google Location Services has been removed to make MapLibre GL Native for Android fully FLOSS ([#379](https://github.com/maplibre/maplibre-gl-native/issues/379)). To migrate:
|
||||
* Include the source code of the removed [`GoogleLocationEngineImpl`](https://github.com/maplibre/maplibre-gl-native/blob/4a34caab7593f4f1b6d8c09c06a5e25d7c6cfc43/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/engine/GoogleLocationEngineImpl.java) in your source tree.
|
||||
* Pass an instance of `LocationEngine` based on `GoogleLocationEngineImpl` to `LocationComponentActivationOptions.Builder.locationEngine`. Refer to how this was done in the now-removed [`LocationEngineProvider`](https://github.com/maplibre/maplibre-gl-native/blob/68d58d6f6f453d5c6cc0fa92fcc6c6cfe0cf967f/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/engine/LocationEngineProvider.java#L59).
|
||||
* The static `LocationEngineResult.extractResult` can no longer extract a `LocationEngineResult` from a Google Play intent. To migrate, include and use the [previous implementation](https://github.com/maplibre/maplibre-gl-native/blob/ea234edf67bb3aec75f077e15c1c30c99756b926/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/engine/LocationEngineResult.java#L97) in your source tree.
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ dependencies {
|
||||
implementation dependenciesList.supportAnnotations
|
||||
implementation dependenciesList.supportFragmentV4
|
||||
implementation dependenciesList.okhttp3
|
||||
implementation dependenciesList.gmsLocation
|
||||
implementation dependenciesList.timber
|
||||
implementation dependenciesList.interpolator
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ class LatLng : Parcelable {
|
||||
@Keep
|
||||
var latitude = 0.0
|
||||
set(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) latitude) {
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) latitude
|
||||
) {
|
||||
require(!latitude.isNaN()) { "latitude must not be NaN" }
|
||||
require(abs(latitude) <= GeometryConstants.MAX_LATITUDE) { "latitude must be between -90 and 90" }
|
||||
field = latitude
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.mapbox.mapboxsdk.camera.CameraUpdate;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngine;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineProvider;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineDefault;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineRequest;
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineResult;
|
||||
import com.mapbox.mapboxsdk.location.modes.CameraMode;
|
||||
@@ -66,7 +66,7 @@ import static com.mapbox.mapboxsdk.location.modes.RenderMode.GPS;
|
||||
* <p>
|
||||
* <strong>
|
||||
* To get the component object use {@link MapboxMap#getLocationComponent()} and activate it with
|
||||
* {@link #activateLocationComponent(Context, Style)} or one of the overloads.
|
||||
* {@link #activateLocationComponent(LocationComponentActivationOptions)}.
|
||||
* Then, manage its visibility with {@link #setLocationComponentEnabled(boolean)}.
|
||||
* The component will not process location updates right after activation, but only after being enabled.
|
||||
* </strong>
|
||||
@@ -76,19 +76,17 @@ import static com.mapbox.mapboxsdk.location.modes.RenderMode.GPS;
|
||||
* {@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.mapboxsdk.location.engine.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.mapboxsdk.location.engine.GoogleLocationEngineImpl} instead.
|
||||
* This component offers a default, built-in {@link LocationEngine} called
|
||||
* {@link com.mapbox.mapboxsdk.location.engine.MapboxFusedLocationEngineImpl}.
|
||||
* If you'd like to utilize the previously available Google Play Services for more precise location updates,
|
||||
* refer to the migration guide of 10.0.0 in the changelog.
|
||||
* 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, Style, boolean)} with false.
|
||||
* To achieve that, set `useDefaultLocationEngine` in {@link LocationComponentActivationOptions} to 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,
|
||||
@@ -105,8 +103,6 @@ public final class LocationComponent {
|
||||
private final Transform transform;
|
||||
private Style style;
|
||||
private LocationComponentOptions options;
|
||||
@NonNull
|
||||
private InternalLocationEngineProvider internalLocationEngineProvider = new InternalLocationEngineProvider();
|
||||
@Nullable
|
||||
private LocationEngine locationEngine;
|
||||
@NonNull
|
||||
@@ -218,7 +214,6 @@ public final class LocationComponent {
|
||||
@NonNull LocationAnimatorCoordinator locationAnimatorCoordinator,
|
||||
@NonNull StaleStateManager staleStateManager,
|
||||
@NonNull CompassEngine compassEngine,
|
||||
@NonNull InternalLocationEngineProvider internalLocationEngineProvider,
|
||||
boolean useSpecializedLocationLayer) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
this.transform = transform;
|
||||
@@ -230,242 +225,10 @@ public final class LocationComponent {
|
||||
this.locationAnimatorCoordinator = locationAnimatorCoordinator;
|
||||
this.staleStateManager = staleStateManager;
|
||||
this.compassEngine = compassEngine;
|
||||
this.internalLocationEngineProvider = internalLocationEngineProvider;
|
||||
this.useSpecializedLocationLayer = useSpecializedLocationLayer;
|
||||
isComponentInitialized = 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)}.
|
||||
* <p>
|
||||
* <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
|
||||
*
|
||||
* @param context the context
|
||||
* @param style the proxy object for current map style. More info at {@link Style}
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style) {
|
||||
activateLocationComponent(context, style,
|
||||
LocationComponentOptions.createFromAttributes(context, R.style.maplibre_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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @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
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
boolean useDefaultLocationEngine) {
|
||||
if (useDefaultLocationEngine) {
|
||||
activateLocationComponent(context, style, R.style.maplibre_LocationComponent);
|
||||
} else {
|
||||
activateLocationComponent(context, style, null, R.style.maplibre_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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @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
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
boolean useDefaultLocationEngine,
|
||||
@NonNull LocationEngineRequest locationEngineRequest) {
|
||||
setLocationEngineRequest(locationEngineRequest);
|
||||
if (useDefaultLocationEngine) {
|
||||
activateLocationComponent(context, style, R.style.maplibre_LocationComponent);
|
||||
} else {
|
||||
activateLocationComponent(context, style, null, R.style.maplibre_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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @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
|
||||
* @param options the options
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
boolean useDefaultLocationEngine,
|
||||
@NonNull LocationEngineRequest locationEngineRequest,
|
||||
@NonNull LocationComponentOptions options) {
|
||||
setLocationEngineRequest(locationEngineRequest);
|
||||
if (useDefaultLocationEngine) {
|
||||
activateLocationComponent(context, style, options);
|
||||
} else {
|
||||
activateLocationComponent(context, style, null, 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)}.
|
||||
* <p>
|
||||
* <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
|
||||
*
|
||||
* @param context the context
|
||||
* @param style the proxy object for current map style. More info at {@link Style}
|
||||
* @param styleRes the LocationComponent style res
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) {
|
||||
activateLocationComponent(context, style, 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)}.
|
||||
* <p>
|
||||
* <strong>Note</strong>: This method will initialize and use an internal {@link LocationEngine} when enabled.
|
||||
* </p>
|
||||
*
|
||||
* @param context the context
|
||||
* @param style the proxy object for current map style. More info at {@link Style}
|
||||
* @param options the options
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@NonNull LocationComponentOptions options) {
|
||||
initialize(context, style, false, options);
|
||||
initializeLocationEngine(context);
|
||||
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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @param locationEngine the engine, or null if you'd like to only force location updates
|
||||
* @param styleRes the LocationComponent style res
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine, @StyleRes int styleRes) {
|
||||
activateLocationComponent(context, style, 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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @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
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine,
|
||||
@NonNull LocationEngineRequest locationEngineRequest, @StyleRes int styleRes) {
|
||||
activateLocationComponent(context, style, 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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @param locationEngine the engine
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine) {
|
||||
activateLocationComponent(context, style, locationEngine, R.style.maplibre_LocationComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will show the location icon and enable the camera tracking the location.
|
||||
*
|
||||
* @param context the context
|
||||
* @param style the proxy object for current map style. More info at {@link Style}
|
||||
* @param locationEngine the engine
|
||||
* @param locationEngineRequest the location request
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine,
|
||||
@NonNull LocationEngineRequest locationEngineRequest) {
|
||||
activateLocationComponent(
|
||||
context,
|
||||
style,
|
||||
locationEngine,
|
||||
locationEngineRequest,
|
||||
R.style.maplibre_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 locationEngine the engine, or null if you'd like to only force location updates
|
||||
* @param style the proxy object for current map style. More info at {@link Style}
|
||||
* @param options the options
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine,
|
||||
@NonNull LocationComponentOptions options) {
|
||||
initialize(context, style, false, options);
|
||||
setLocationEngine(locationEngine);
|
||||
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 style the proxy object for current map style. More info at {@link Style}
|
||||
* @param locationEngine the engine, or null if you'd like to only force location updates
|
||||
* @param locationEngineRequest the location request
|
||||
* @param options the options
|
||||
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
|
||||
@Nullable LocationEngine locationEngine,
|
||||
@NonNull LocationEngineRequest locationEngineRequest,
|
||||
@NonNull LocationComponentOptions options) {
|
||||
initialize(context, style, false, options);
|
||||
setLocationEngineRequest(locationEngineRequest);
|
||||
setLocationEngine(locationEngine);
|
||||
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)}.
|
||||
@@ -503,7 +266,7 @@ public final class LocationComponent {
|
||||
setLocationEngine(locationEngine);
|
||||
} else {
|
||||
if (activationOptions.useDefaultLocationEngine()) {
|
||||
initializeLocationEngine(activationOptions.context());
|
||||
setLocationEngine(LocationEngineDefault.INSTANCE.getDefaultLocationEngine(activationOptions.context()));
|
||||
} else {
|
||||
setLocationEngine(null);
|
||||
}
|
||||
@@ -1354,13 +1117,6 @@ public final class LocationComponent {
|
||||
onLocationLayerStart();
|
||||
}
|
||||
|
||||
private void initializeLocationEngine(@NonNull Context context) {
|
||||
if (this.locationEngine != null) {
|
||||
this.locationEngine.removeLocationUpdates(currentLocationEngineListener);
|
||||
}
|
||||
setLocationEngine(internalLocationEngineProvider.getBestLocationEngine(context, false));
|
||||
}
|
||||
|
||||
private void updateCompassListenerState(boolean canListen) {
|
||||
if (compassEngine != null) {
|
||||
if (!canListen) {
|
||||
@@ -1712,12 +1468,6 @@ public final class LocationComponent {
|
||||
}
|
||||
};
|
||||
|
||||
static class InternalLocationEngineProvider {
|
||||
LocationEngine getBestLocationEngine(@NonNull Context context, boolean background) {
|
||||
return LocationEngineProvider.getBestLocationEngine(context, background);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkActivationState() {
|
||||
if (!isComponentInitialized) {
|
||||
throw new LocationComponentNotInitializedException();
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
package com.mapbox.mapboxsdk.location.engine;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
import com.google.android.gms.location.LocationCallback;
|
||||
import com.google.android.gms.location.LocationRequest;
|
||||
import com.google.android.gms.location.LocationResult;
|
||||
import com.google.android.gms.location.LocationServices;
|
||||
import com.google.android.gms.location.Priority;
|
||||
import com.google.android.gms.tasks.OnFailureListener;
|
||||
import com.google.android.gms.tasks.OnSuccessListener;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wraps implementation of Fused Location Provider
|
||||
*/
|
||||
class GoogleLocationEngineImpl implements LocationEngineImpl<LocationCallback> {
|
||||
private final FusedLocationProviderClient fusedLocationProviderClient;
|
||||
|
||||
@VisibleForTesting
|
||||
GoogleLocationEngineImpl(FusedLocationProviderClient fusedLocationProviderClient) {
|
||||
this.fusedLocationProviderClient = fusedLocationProviderClient;
|
||||
}
|
||||
|
||||
GoogleLocationEngineImpl(@NonNull Context context) {
|
||||
this.fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LocationCallback createListener(LocationEngineCallback<LocationEngineResult> callback) {
|
||||
return new GoogleLocationEngineCallbackTransport(callback);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void getLastLocation(@NonNull LocationEngineCallback<LocationEngineResult> callback)
|
||||
throws SecurityException {
|
||||
GoogleLastLocationEngineCallbackTransport transport =
|
||||
new GoogleLastLocationEngineCallbackTransport(callback);
|
||||
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(transport).addOnFailureListener(transport);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void requestLocationUpdates(@NonNull LocationEngineRequest request,
|
||||
@NonNull LocationCallback listener,
|
||||
@Nullable Looper looper) throws SecurityException {
|
||||
fusedLocationProviderClient.requestLocationUpdates(toGMSLocationRequest(request), listener, looper);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public void requestLocationUpdates(@NonNull LocationEngineRequest request,
|
||||
@NonNull PendingIntent pendingIntent) throws SecurityException {
|
||||
fusedLocationProviderClient.requestLocationUpdates(toGMSLocationRequest(request), pendingIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocationUpdates(@NonNull LocationCallback listener) {
|
||||
if (listener != null) {
|
||||
fusedLocationProviderClient.removeLocationUpdates(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocationUpdates(PendingIntent pendingIntent) {
|
||||
if (pendingIntent != null) {
|
||||
fusedLocationProviderClient.removeLocationUpdates(pendingIntent);
|
||||
}
|
||||
}
|
||||
|
||||
private static LocationRequest toGMSLocationRequest(LocationEngineRequest request) {
|
||||
LocationRequest.Builder builder = new LocationRequest.Builder(request.getInterval());
|
||||
builder.setMinUpdateIntervalMillis(request.getFastestInterval());
|
||||
builder.setMinUpdateDistanceMeters(request.getDisplacement());
|
||||
builder.setMaxUpdateDelayMillis(request.getMaxWaitTime());
|
||||
builder.setPriority(toGMSLocationPriority(request.getPriority()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static int toGMSLocationPriority(int enginePriority) {
|
||||
switch (enginePriority) {
|
||||
case LocationEngineRequest.PRIORITY_HIGH_ACCURACY:
|
||||
return Priority.PRIORITY_HIGH_ACCURACY;
|
||||
case LocationEngineRequest.PRIORITY_BALANCED_POWER_ACCURACY:
|
||||
return Priority.PRIORITY_BALANCED_POWER_ACCURACY;
|
||||
case LocationEngineRequest.PRIORITY_LOW_POWER:
|
||||
return Priority.PRIORITY_LOW_POWER;
|
||||
case LocationEngineRequest.PRIORITY_NO_POWER:
|
||||
default:
|
||||
return Priority.PRIORITY_PASSIVE;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class GoogleLocationEngineCallbackTransport extends LocationCallback {
|
||||
private final LocationEngineCallback<LocationEngineResult> callback;
|
||||
|
||||
GoogleLocationEngineCallbackTransport(LocationEngineCallback<LocationEngineResult> callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationResult(LocationResult locationResult) {
|
||||
super.onLocationResult(locationResult);
|
||||
List<Location> locations = locationResult.getLocations();
|
||||
if (!locations.isEmpty()) {
|
||||
callback.onSuccess(LocationEngineResult.create(locations));
|
||||
} else {
|
||||
callback.onFailure(new Exception("Unavailable location"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static final class GoogleLastLocationEngineCallbackTransport
|
||||
implements OnSuccessListener<Location>, OnFailureListener {
|
||||
private final LocationEngineCallback<LocationEngineResult> callback;
|
||||
|
||||
GoogleLastLocationEngineCallbackTransport(LocationEngineCallback<LocationEngineResult> callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Location location) {
|
||||
callback.onSuccess(location != null ? LocationEngineResult.create(location) :
|
||||
LocationEngineResult.create(Collections.<Location>emptyList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Exception e) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mapbox.mapboxsdk.location.engine
|
||||
|
||||
import android.content.Context
|
||||
|
||||
object LocationEngineDefault {
|
||||
/**
|
||||
* Returns the default `LocationEngine`.
|
||||
*/
|
||||
fun getDefaultLocationEngine(context: Context): LocationEngine {
|
||||
return LocationEngineProxy(MapboxFusedLocationEngineImpl(context.applicationContext))
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import androidx.annotation.Nullable;
|
||||
*
|
||||
* @param <T> location listener object type
|
||||
*/
|
||||
interface LocationEngineImpl<T> {
|
||||
public interface LocationEngineImpl<T> {
|
||||
@NonNull
|
||||
T createListener(LocationEngineCallback<LocationEngineResult> callback);
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.mapbox.mapboxsdk.location.engine;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
import static com.mapbox.mapboxsdk.location.engine.Utils.checkNotNull;
|
||||
import static com.mapbox.mapboxsdk.location.engine.Utils.isOnClasspath;
|
||||
|
||||
/**
|
||||
* The main entry point for location engine integration.
|
||||
*/
|
||||
public final class LocationEngineProvider {
|
||||
private static final String GOOGLE_LOCATION_SERVICES = "com.google.android.gms.location.LocationServices";
|
||||
private static final String GOOGLE_API_AVAILABILITY = "com.google.android.gms.common.GoogleApiAvailability";
|
||||
|
||||
private LocationEngineProvider() {
|
||||
// prevent instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance to the best location engine, given the included libraries.
|
||||
*
|
||||
* @param context {@link Context}.
|
||||
* @param background true if background optimized engine is desired (note: parameter deprecated)
|
||||
* @return a unique instance of {@link LocationEngine} every time method is called.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@NonNull
|
||||
@Deprecated
|
||||
public static LocationEngine getBestLocationEngine(@NonNull Context context, boolean background) {
|
||||
return getBestLocationEngine(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance to the best location engine, given the included libraries.
|
||||
*
|
||||
* @param context {@link Context}.
|
||||
* @return a unique instance of {@link LocationEngine} every time method is called.
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@NonNull
|
||||
public static LocationEngine getBestLocationEngine(@NonNull Context context) {
|
||||
checkNotNull(context, "context == null");
|
||||
|
||||
boolean hasGoogleLocationServices = isOnClasspath(GOOGLE_LOCATION_SERVICES);
|
||||
if (isOnClasspath(GOOGLE_API_AVAILABILITY)) {
|
||||
// Check Google Play services APK is available and up-to-date on this device
|
||||
hasGoogleLocationServices &= GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
|
||||
== ConnectionResult.SUCCESS;
|
||||
}
|
||||
return getLocationEngine(context, hasGoogleLocationServices);
|
||||
}
|
||||
|
||||
private static LocationEngine getLocationEngine(Context context, boolean isGoogle) {
|
||||
return isGoogle ? new LocationEngineProxy<>(new GoogleLocationEngineImpl(context.getApplicationContext())) :
|
||||
new LocationEngineProxy<>(new MapboxFusedLocationEngineImpl(context.getApplicationContext()));
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.mapbox.mapboxsdk.location.engine.Utils.checkNotNull;
|
||||
|
||||
class LocationEngineProxy<T> implements LocationEngine {
|
||||
public class LocationEngineProxy<T> implements LocationEngine {
|
||||
private final LocationEngineImpl<T> locationEngineImpl;
|
||||
private Map<LocationEngineCallback<LocationEngineResult>, T> listeners;
|
||||
|
||||
|
||||
@@ -7,14 +7,10 @@ import android.location.LocationManager;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.gms.location.LocationResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.mapbox.mapboxsdk.location.engine.Utils.isOnClasspath;
|
||||
|
||||
/**
|
||||
* A wrapper class representing location result from the location engine.
|
||||
* <p>
|
||||
@@ -23,8 +19,6 @@ import static com.mapbox.mapboxsdk.location.engine.Utils.isOnClasspath;
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class LocationEngineResult {
|
||||
private static final String GOOGLE_PLAY_LOCATION_RESULT = "com.google.android.gms.location.LocationResult";
|
||||
|
||||
private final List<Location> locations;
|
||||
|
||||
private LocationEngineResult(List<Location> locations) {
|
||||
@@ -95,16 +89,7 @@ public final class LocationEngineResult {
|
||||
*/
|
||||
@Nullable
|
||||
public static LocationEngineResult extractResult(Intent intent) {
|
||||
LocationEngineResult result = null;
|
||||
if (isOnClasspath(GOOGLE_PLAY_LOCATION_RESULT)) {
|
||||
result = extractGooglePlayResult(intent);
|
||||
}
|
||||
return result == null ? extractAndroidResult(intent) : result;
|
||||
}
|
||||
|
||||
private static LocationEngineResult extractGooglePlayResult(Intent intent) {
|
||||
LocationResult result = LocationResult.extractResult(intent);
|
||||
return result != null ? LocationEngineResult.create(result.getLocations()) : null;
|
||||
return extractAndroidResult(intent);
|
||||
}
|
||||
|
||||
private static LocationEngineResult extractAndroidResult(Intent intent) {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.mapbox.mapboxsdk.location
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.content.res.TypedArray
|
||||
import android.location.Location
|
||||
import android.os.Looper
|
||||
import com.mapbox.mapboxsdk.R
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition
|
||||
import com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngine
|
||||
@@ -69,60 +66,45 @@ class LocationComponentTest {
|
||||
@Mock
|
||||
private lateinit var staleStateManager: StaleStateManager
|
||||
|
||||
@Mock
|
||||
private lateinit var locationEngineProvider: LocationComponent.InternalLocationEngineProvider
|
||||
|
||||
@Mock
|
||||
private lateinit var style: Style
|
||||
|
||||
private lateinit var developerAnimationListeners: List<MapboxMap.OnDeveloperAnimationListener>
|
||||
|
||||
private val defaultOptions: LocationComponentActivationOptions
|
||||
get() = LocationComponentActivationOptions.builder(context, style).locationEngine(locationEngine).locationEngineRequest(locationEngineRequest).locationComponentOptions(locationComponentOptions).build()
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
developerAnimationListeners = mutableListOf()
|
||||
locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, false)
|
||||
doReturn(locationEngine).`when`(locationEngineProvider).getBestLocationEngine(context, false)
|
||||
locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, false)
|
||||
doReturn(style).`when`(mapboxMap).style
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activateWithRequestTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
|
||||
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
|
||||
|
||||
doReturn(mock(TypedArray::class.java)).`when`(context)
|
||||
.obtainStyledAttributes(R.style.maplibre_LocationComponent, R.styleable.maplibre_LocationComponent)
|
||||
|
||||
val resources = mock(Resources::class.java)
|
||||
|
||||
doReturn(resources).`when`(context).resources
|
||||
doReturn(0f).`when`(resources)
|
||||
.getDimension(R.dimen.maplibre_locationComponentTrackingMultiFingerMoveThreshold)
|
||||
doReturn(0f).`when`(resources)
|
||||
.getDimension(R.dimen.maplibre_locationComponentTrackingMultiFingerMoveThreshold)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), true, locationEngineRequest)
|
||||
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
|
||||
`when`(style.isFullyLoaded).thenReturn(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activateWithDefaultLocationEngineRequestAndOptionsTestDefaultLocationEngine() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), true, locationEngineRequest, locationComponentOptions)
|
||||
val options = LocationComponentActivationOptions.builder(context, style).locationEngine(locationEngine).locationEngineRequest(locationEngineRequest).locationComponentOptions(locationComponentOptions).build()
|
||||
locationComponent.activateLocationComponent(options)
|
||||
|
||||
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
|
||||
Assert.assertNotNull(locationComponent.locationEngine)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun activateWithDefaultLocationEngineRequestAndOptionsTestCustomLocationEngine() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), false, locationEngineRequest, locationComponentOptions)
|
||||
val options = LocationComponentActivationOptions.builder(context, style).useDefaultLocationEngine(false).locationEngineRequest(locationEngineRequest).locationComponentOptions(locationComponentOptions).build()
|
||||
locationComponent.activateLocationComponent(options)
|
||||
|
||||
Assert.assertEquals(locationEngineRequest, locationComponent.locationEngineRequest)
|
||||
Assert.assertNull(locationComponent.locationEngine)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun locationUpdatesWhenEnabledDisableTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
|
||||
verify(locationEngine, times(0)).removeLocationUpdates(currentListener)
|
||||
verify(locationEngine, times(0)).requestLocationUpdates(eq(locationEngineRequest), eq(currentListener), any(Looper::class.java))
|
||||
|
||||
@@ -140,7 +122,8 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun locationUpdatesWhenStartedStoppedTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
@@ -153,7 +136,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun locationUpdatesWhenNewRequestTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
@@ -165,7 +148,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun lastLocationUpdateOnStartTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
@@ -174,7 +157,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun transitionCallbackFinishedTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -192,7 +175,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun transitionCallbackCanceledTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -210,7 +193,8 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun transitionCustomFinishedTest() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -228,7 +212,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_listenWhenConsumedByNoneCamera() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -240,7 +224,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_listenWhenConsumedByTrackingCamera() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -252,7 +236,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_listenWhenConsumedByLayer() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -264,7 +248,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_notListenWhenNotConsumed() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -283,7 +267,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_removeListenerOnChange() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -297,7 +281,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_removeListenerOnStop() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -310,7 +294,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_reAddListenerOnStart() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -324,7 +308,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_removeListenerOnStyleStartLoad() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -337,7 +321,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_reAddListenerOnStyleLoadFinished() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -351,7 +335,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_reAddListenerOnlyWhenEnabled() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -367,7 +351,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_notAdListenerWhenDisabled() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
|
||||
@@ -378,7 +362,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_notAdListenerWhenStopped() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
|
||||
@@ -389,7 +373,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun compass_notAddListenerWhenLayerNotReady() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.onStart()
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
@@ -406,7 +390,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun developerAnimationCalled() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
for (listener in developerAnimationListeners) {
|
||||
listener.onDeveloperAnimationStarted()
|
||||
@@ -416,7 +400,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun internal_cameraTrackingChangedListener_onCameraTrackingDismissed() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
val cameraChangeListener: OnCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener::class.java)
|
||||
@@ -429,7 +413,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun internal_cameraTrackingChangedListener_onCameraTrackingChanged() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
val cameraValueListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java)
|
||||
@@ -451,7 +435,7 @@ class LocationComponentTest {
|
||||
|
||||
@Test
|
||||
fun internal_renderModeChangedListener_onRenderModeChanged() {
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
val cameraListener: AnimatorListenerHolder = mock(AnimatorListenerHolder::class.java)
|
||||
@@ -476,7 +460,6 @@ class LocationComponentTest {
|
||||
val projection: Projection = mock(Projection::class.java)
|
||||
`when`(projection.getMetersPerPixelAtLatitude(location.latitude)).thenReturn(10.0)
|
||||
`when`(mapboxMap.projection).thenReturn(projection)
|
||||
`when`(style.isFullyLoaded).thenReturn(true)
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
|
||||
locationComponent.activateLocationComponent(
|
||||
@@ -500,7 +483,7 @@ class LocationComponentTest {
|
||||
@Test
|
||||
fun tiltWhileTracking_notReady() {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
val callback = mock(MapboxMap.CancelableCallback::class.java)
|
||||
@@ -514,7 +497,7 @@ class LocationComponentTest {
|
||||
fun tiltWhileTracking_notTracking() {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.NONE)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -530,7 +513,7 @@ class LocationComponentTest {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING)
|
||||
`when`(locationCameraController.isTransitioning).thenReturn(true)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -546,7 +529,7 @@ class LocationComponentTest {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING)
|
||||
`when`(locationCameraController.isTransitioning).thenReturn(false)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -560,7 +543,7 @@ class LocationComponentTest {
|
||||
@Test
|
||||
fun zoomWhileTracking_notReady() {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
|
||||
val callback = mock(MapboxMap.CancelableCallback::class.java)
|
||||
@@ -574,7 +557,7 @@ class LocationComponentTest {
|
||||
fun zoomWhileTracking_notTracking() {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.NONE)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -590,7 +573,7 @@ class LocationComponentTest {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING)
|
||||
`when`(locationCameraController.isTransitioning).thenReturn(true)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -606,7 +589,7 @@ class LocationComponentTest {
|
||||
`when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT)
|
||||
`when`(locationCameraController.cameraMode).thenReturn(CameraMode.TRACKING)
|
||||
`when`(locationCameraController.isTransitioning).thenReturn(false)
|
||||
locationComponent.activateLocationComponent(context, mock(Style::class.java), locationEngine, locationEngineRequest, locationComponentOptions)
|
||||
locationComponent.activateLocationComponent(defaultOptions)
|
||||
locationComponent.isLocationComponentEnabled = true
|
||||
locationComponent.onStart()
|
||||
|
||||
@@ -624,7 +607,6 @@ class LocationComponentTest {
|
||||
val projection: Projection = mock(Projection::class.java)
|
||||
`when`(projection.getMetersPerPixelAtLatitude(location.latitude)).thenReturn(10.0)
|
||||
`when`(mapboxMap.projection).thenReturn(projection)
|
||||
`when`(style.isFullyLoaded).thenReturn(true)
|
||||
locationComponent.activateLocationComponent(
|
||||
LocationComponentActivationOptions.builder(context, style)
|
||||
.locationComponentOptions(locationComponentOptions)
|
||||
@@ -643,8 +625,7 @@ class LocationComponentTest {
|
||||
fun newLocation_accuracy_indicatorLayerRadiusValue() {
|
||||
val location = Location("test")
|
||||
location.accuracy = 50f
|
||||
`when`(style.isFullyLoaded).thenReturn(true)
|
||||
locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, locationEngineProvider, true)
|
||||
locationComponent = LocationComponent(mapboxMap, transform, developerAnimationListeners, currentListener, lastListener, locationLayerController, locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine, true)
|
||||
locationComponent.activateLocationComponent(
|
||||
LocationComponentActivationOptions.builder(context, style)
|
||||
.locationComponentOptions(locationComponentOptions)
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
package com.mapbox.mapboxsdk.location.engine;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
import com.google.android.gms.location.LocationCallback;
|
||||
import com.google.android.gms.location.LocationRequest;
|
||||
import com.google.android.gms.location.LocationResult;
|
||||
import com.google.android.gms.tasks.OnSuccessListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GoogleLocationEngineImplAdditionalTest {
|
||||
private static final long INTERVAL = 1000L;
|
||||
private LocationEngineProxy engine;
|
||||
private Location location;
|
||||
private List<Location> locationList = new ArrayList<>();
|
||||
private FusedLocationProviderClient fusedLocationProviderClient;
|
||||
private Task<Void> mockTask;
|
||||
private Task<Location> mockLocationTask;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
location = mock(Location.class);
|
||||
when(location.getLatitude()).thenReturn(1.0);
|
||||
when(location.getLongitude()).thenReturn(2.0);
|
||||
locationList.clear();
|
||||
locationList.add(location);
|
||||
fusedLocationProviderClient = mock(FusedLocationProviderClient.class);
|
||||
mockTask = mock(Task.class);
|
||||
mockLocationTask = mock(Task.class);
|
||||
when(fusedLocationProviderClient.getLastLocation()).thenReturn(mockLocationTask);
|
||||
when(fusedLocationProviderClient
|
||||
.requestLocationUpdates(any(LocationRequest.class), any(LocationCallback.class), any(Looper.class)))
|
||||
.thenAnswer(new Answer<Task<Void>>() {
|
||||
@Override
|
||||
public Task<Void> answer(InvocationOnMock invocation) {
|
||||
LocationCallback listener = (LocationCallback) invocation.getArguments()[1];
|
||||
listener.onLocationResult(LocationResult.create(locationList));
|
||||
return mockTask;
|
||||
}
|
||||
});
|
||||
|
||||
engine = new LocationEngineProxy<>(new GoogleLocationEngineImpl(fusedLocationProviderClient));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkGetLastLocation() throws InterruptedException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
when(mockLocationTask.addOnSuccessListener(any(OnSuccessListener.class)))
|
||||
.thenAnswer(new Answer<Object>() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
OnSuccessListener listener = (OnSuccessListener) invocation.getArguments()[0];
|
||||
listener.onSuccess(location);
|
||||
return mock(Task.class);
|
||||
}
|
||||
});
|
||||
engine.getLastLocation(new LocationEngineCallback<LocationEngineResult>() {
|
||||
@Override
|
||||
public void onSuccess(LocationEngineResult result) {
|
||||
List<Location> list = result.getLocations();
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(1.0, list.get(0).getLatitude(), 0);
|
||||
assertEquals(2.0, list.get(0).getLongitude(), 0);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Exception exception) {
|
||||
|
||||
}
|
||||
});
|
||||
assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkRequestAndRemoveLocationUpdates() throws InterruptedException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
LocationEngineCallback<LocationEngineResult> engineCallback = new LocationEngineCallback<LocationEngineResult>() {
|
||||
@Override
|
||||
public void onSuccess(LocationEngineResult result) {
|
||||
List<Location> list = result.getLocations();
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(1.0, list.get(0).getLatitude(), 0);
|
||||
assertEquals(2.0, list.get(0).getLongitude(), 0);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Exception exception) {
|
||||
|
||||
}
|
||||
};
|
||||
engine.requestLocationUpdates(getRequest(INTERVAL, LocationEngineRequest.PRIORITY_HIGH_ACCURACY),
|
||||
engineCallback, mock(Looper.class));
|
||||
assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
assertNotNull(engine.removeListener(engineCallback));
|
||||
}
|
||||
|
||||
private static LocationEngineRequest getRequest(long interval, int priority) {
|
||||
return new LocationEngineRequest.Builder(interval).setPriority(priority).build();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.mapbox.mapboxsdk.location.engine;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
|
||||
import com.google.android.gms.location.FusedLocationProviderClient;
|
||||
import com.google.android.gms.location.LocationCallback;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GoogleLocationEngineImplTest {
|
||||
@Mock
|
||||
private FusedLocationProviderClient fusedLocationProviderClientMock;
|
||||
|
||||
private LocationEngine engine;
|
||||
private GoogleLocationEngineImpl googleLocationEngineImpl;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
googleLocationEngineImpl = new GoogleLocationEngineImpl(fusedLocationProviderClientMock);
|
||||
engine = new LocationEngineProxy<>(googleLocationEngineImpl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeLocationUpdatesForInvalidListener() {
|
||||
LocationEngineCallback<LocationEngineResult> callback = mock(LocationEngineCallback.class);
|
||||
engine.removeLocationUpdates(callback);
|
||||
verify(fusedLocationProviderClientMock, never()).removeLocationUpdates(any(LocationCallback.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeLocationUpdatesForPendingIntent() {
|
||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||
engine.removeLocationUpdates(pendingIntent);
|
||||
verify(fusedLocationProviderClientMock, times(1))
|
||||
.removeLocationUpdates(any(PendingIntent.class));
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void getLastLocationNullCallback() {
|
||||
engine.getLastLocation(null);
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void requestLocationUpdatesNullCallback() {
|
||||
engine.requestLocationUpdates(null, null, null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
reset(fusedLocationProviderClientMock);
|
||||
engine = null;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.mapbox.mapboxsdk.location.engine;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LocationEngineProviderTest {
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void passNullContext() {
|
||||
LocationEngineProvider.getBestLocationEngine(null, false);
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,6 @@ dependencies {
|
||||
|
||||
implementation dependenciesList.multidex
|
||||
|
||||
implementation dependenciesList.gmsLocation
|
||||
implementation dependenciesList.timber
|
||||
|
||||
implementation dependenciesList.okhttp3
|
||||
|
||||
@@ -71,4 +71,4 @@ class StyleLoaderTest : EspressoTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,4 +28,4 @@ class FontUtilsTest {
|
||||
val actual = FontUtils.extractValidFont(null)
|
||||
Assert.assertNull(actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds
|
||||
import com.mapbox.mapboxsdk.location.LocationComponent
|
||||
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngine
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineProvider
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineDefault
|
||||
import com.mapbox.mapboxsdk.location.engine.LocationEngineRequest
|
||||
import com.mapbox.mapboxsdk.location.modes.RenderMode
|
||||
import com.mapbox.mapboxsdk.location.permissions.PermissionsListener
|
||||
@@ -29,7 +29,7 @@ class ManualLocationUpdatesActivity : AppCompatActivity(), OnMapReadyCallback {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_location_manual_update)
|
||||
locationEngine = LocationEngineProvider.getBestLocationEngine(this, false)
|
||||
locationEngine = LocationEngineDefault.getDefaultLocationEngine(mapView.context)
|
||||
val fabManualUpdate = findViewById<FloatingActionButton>(R.id.fabManualLocationChange)
|
||||
fabManualUpdate.setOnClickListener { v: View? ->
|
||||
if (locationComponent != null && locationComponent!!.locationEngine == null) {
|
||||
|
||||
@@ -37,7 +37,6 @@ ext {
|
||||
kotlin : '1.7.20',
|
||||
licenses : '0.8.80',
|
||||
lint : '30.3.1',
|
||||
gms : '21.0.1',
|
||||
// jacoco : '0.8.5',
|
||||
appcenter : '1.5',
|
||||
commonsIO : '2.11.0',
|
||||
@@ -75,7 +74,6 @@ ext {
|
||||
|
||||
appCenter : "com.microsoft.appcenter:espresso-test-extension:${versions.appcenter}",
|
||||
commonsIO : "commons-io:commons-io:${versions.commonsIO}",
|
||||
gmsLocation : "com.google.android.gms:play-services-location:${versions.gms}",
|
||||
timber : "com.jakewharton.timber:timber:${versions.timber}",
|
||||
okhttp3 : "com.squareup.okhttp3:okhttp:${versions.okhttp}",
|
||||
leakCanary : "com.squareup.leakcanary:leakcanary-android:${versions.leakCanary}",
|
||||
|
||||
Reference in New Issue
Block a user