diff options
author | kevin <kevin.li@mapbox.com> | 2019-01-16 08:29:58 -0800 |
---|---|---|
committer | kevin <kevin.li@mapbox.com> | 2019-01-16 08:29:58 -0800 |
commit | c09831cda04bf97c1c208cacfaaa660c36003cbd (patch) | |
tree | e1ff23c5feaea81d0e6ec096b17e5f223204c2d4 /platform/android/MapboxGLAndroidSDK | |
parent | 788158cc5608bc428b13ad0ef6215626e1acaffd (diff) | |
parent | b23a6122259cac97f174dddb978437dd3a58a5df (diff) | |
download | qtlocation-mapboxgl-upstream/no-v7.tar.gz |
Merge branch 'release-horchata' into no-v7upstream/no-v7
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK')
24 files changed, 745 insertions, 79 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 3959d2cf3c..4d680f8873 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -68,7 +68,7 @@ public final class Mapbox { } /** - * Access token for this application. + * Get the current active access token for this application. * * @return Mapbox access token */ @@ -79,6 +79,15 @@ public final class Mapbox { } /** + * Set the current active accessToken. + */ + public static void setAccessToken(String accessToken) { + validateMapbox(); + INSTANCE.accessToken = accessToken; + FileSource.getInstance(getApplicationContext()).setAccessToken(accessToken); + } + + /** * Application context * * @return the application context diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java index 3691bdc0ea..33efa06226 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java @@ -55,11 +55,17 @@ public interface CompassEngine { /** * Lifecycle method that can be used for adding or releasing resources. + * + * @deprecated Use {@link #addCompassListener(CompassListener)} */ + @Deprecated void onStart(); /** * Lifecycle method that can be used for adding or releasing resources. + * + * @deprecated Use {@link #removeCompassListener(CompassListener)} */ + @Deprecated void onStop(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java index 3e5eb7f258..c44218a1d1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java @@ -7,7 +7,7 @@ public interface CompassListener { /** * Callback's invoked when a new compass update occurs. You can listen into the compass updates - * using {@link LocationComponent#addCompassListener(CompassListener)} and implementing these + * using {@link CompassEngine#addCompassListener(CompassListener)} and implementing these * callbacks. Note that this interface is also used internally to to update the UI chevron/arrow. * * @param userHeading the new compass heading diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java index 0a6c9b5ddc..4ac124ef24 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java @@ -1,7 +1,6 @@ package com.mapbox.mapboxsdk.location; import android.animation.Animator; -import android.animation.AnimatorSet; import android.location.Location; import android.os.SystemClock; import android.support.annotation.NonNull; @@ -13,13 +12,13 @@ import android.view.animation.LinearInterpolator; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; import java.util.ArrayList; import java.util.List; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.COMPASS_UPDATE_RATE_MS; -import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.MAX_ANIMATION_DURATION_MS; import static com.mapbox.mapboxsdk.location.LocationComponentConstants.TRANSITION_ANIMATION_DURATION_MS; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_CAMERA_COMPASS_BEARING; @@ -31,6 +30,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BE import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_TILT; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_ZOOM; +import static com.mapbox.mapboxsdk.location.Utils.immediateAnimation; final class LocationAnimatorCoordinator { @@ -39,11 +39,20 @@ final class LocationAnimatorCoordinator { final List<MapboxAnimator.OnLayerAnimationsValuesChangeListener> layerListeners = new ArrayList<>(); final List<MapboxAnimator.OnCameraAnimationsValuesChangeListener> cameraListeners = new ArrayList<>(); + private final Projection projection; private Location previousLocation; private float previousAccuracyRadius = -1; private float previousCompassBearing = -1; private long locationUpdateTimestamp = -1; private float durationMultiplier; + private final MapboxAnimatorSetProvider animatorSetProvider; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; + + LocationAnimatorCoordinator(@NonNull Projection projection, @NonNull MapboxAnimatorSetProvider animatorSetProvider) { + this.projection = projection; + this.animatorSetProvider = animatorSetProvider; + } void addLayerListener(MapboxAnimator.OnLayerAnimationsValuesChangeListener listener) { layerListeners.add(listener); @@ -81,8 +90,8 @@ final class LocationAnimatorCoordinator { updateLayerAnimators(previousLayerLatLng, targetLatLng, previousLayerBearing, targetLayerBearing); updateCameraAnimators(previousCameraLatLng, previousCameraBearing, targetLatLng, targetCameraBearing); - boolean snap = immediateAnimation(previousCameraLatLng, targetLatLng, currentCameraPosition.zoom) - || immediateAnimation(previousLayerLatLng, targetLatLng, currentCameraPosition.zoom); + boolean snap = immediateAnimation(projection, previousCameraLatLng, targetLatLng) + || immediateAnimation(projection, previousLayerLatLng, targetLatLng); playLocationAnimators(snap ? 0 : getAnimationDuration()); previousLocation = newLocation; @@ -97,7 +106,7 @@ final class LocationAnimatorCoordinator { float previousCameraBearing = (float) currentCameraPosition.bearing; updateCompassAnimators(targetCompassBearing, previousLayerBearing, previousCameraBearing); - playCompassAnimators(COMPASS_UPDATE_RATE_MS); + playCompassAnimators(compassAnimationEnabled ? COMPASS_UPDATE_RATE_MS : 0); previousCompassBearing = targetCompassBearing; } @@ -109,7 +118,7 @@ final class LocationAnimatorCoordinator { float previousAccuracyRadius = getPreviousAccuracyRadius(); updateAccuracyAnimators(targetAccuracyRadius, previousAccuracyRadius); - playAccuracyAnimator(noAnimation ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION); + playAccuracyAnimator(noAnimation || !accuracyAnimationEnabled ? 0 : ACCURACY_RADIUS_ANIMATION_DURATION); this.previousAccuracyRadius = targetAccuracyRadius; } @@ -249,27 +258,20 @@ final class LocationAnimatorCoordinator { locationAnimators.add(animatorArray.get(ANIMATOR_LAYER_GPS_BEARING)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_LATLNG)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_GPS_BEARING)); - AnimatorSet locationAnimatorSet = new AnimatorSet(); - locationAnimatorSet.playTogether(locationAnimators); - locationAnimatorSet.setInterpolator(new LinearInterpolator()); - locationAnimatorSet.setDuration(duration); - locationAnimatorSet.start(); + animatorSetProvider.startAnimation(locationAnimators, new LinearInterpolator(), duration); } private void playCompassAnimators(long duration) { List<Animator> compassAnimators = new ArrayList<>(); compassAnimators.add(animatorArray.get(ANIMATOR_LAYER_COMPASS_BEARING)); compassAnimators.add(animatorArray.get(ANIMATOR_CAMERA_COMPASS_BEARING)); - AnimatorSet compassAnimatorSet = new AnimatorSet(); - compassAnimatorSet.playTogether(compassAnimators); - compassAnimatorSet.setDuration(duration); - compassAnimatorSet.start(); + animatorSetProvider.startAnimation(compassAnimators, new LinearInterpolator(), duration); } private void playAccuracyAnimator(long duration) { - MapboxAnimator animator = animatorArray.get(ANIMATOR_LAYER_ACCURACY); - animator.setDuration(duration); - animator.start(); + List<Animator> accuracyAnimators = new ArrayList<>(); + accuracyAnimators.add(animatorArray.get(ANIMATOR_LAYER_ACCURACY)); + animatorSetProvider.startAnimation(accuracyAnimators, new LinearInterpolator(), duration); } private void playZoomAnimator(long duration) { @@ -288,11 +290,7 @@ final class LocationAnimatorCoordinator { List<Animator> locationAnimators = new ArrayList<>(); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_LATLNG)); locationAnimators.add(animatorArray.get(ANIMATOR_CAMERA_GPS_BEARING)); - AnimatorSet locationAnimatorSet = new AnimatorSet(); - locationAnimatorSet.playTogether(locationAnimators); - locationAnimatorSet.setInterpolator(new FastOutSlowInInterpolator()); - locationAnimatorSet.setDuration(duration); - locationAnimatorSet.start(); + animatorSetProvider.startAnimation(locationAnimators, new FastOutSlowInInterpolator(), duration); } void resetAllCameraAnimations(CameraPosition currentCameraPosition, boolean isGpsNorth) { @@ -317,7 +315,7 @@ final class LocationAnimatorCoordinator { createNewAnimator(ANIMATOR_CAMERA_LATLNG, new CameraLatLngAnimator(previousCameraTarget, currentTarget, cameraListeners)); - return immediateAnimation(previousCameraTarget, currentTarget, currentCameraPosition.zoom); + return immediateAnimation(projection, previousCameraTarget, currentTarget); } private void resetCameraGpsBearingAnimation(CameraPosition currentCameraPosition, boolean isGpsNorth) { @@ -382,12 +380,11 @@ final class LocationAnimatorCoordinator { this.durationMultiplier = trackingAnimationDurationMultiplier; } - private boolean immediateAnimation(LatLng current, LatLng target, double zoom) { - // TODO: calculate the value based on the projection - double distance = current.distanceTo(target); - if (zoom > 10) { - distance *= zoom; - } - return distance > INSTANT_LOCATION_TRANSITION_THRESHOLD; + void setCompassAnimationEnabled(boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + } + + void setAccuracyAnimationEnabled(boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index e3194df009..340ee3d0f2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -164,6 +164,11 @@ final class LocationCameraController implements MapboxAnimator.OnCameraAnimation } } + boolean isConsumingCompass() { + return cameraMode == CameraMode.TRACKING_COMPASS + || cameraMode == CameraMode.NONE_COMPASS; + } + private boolean isLocationTracking() { return cameraMode == CameraMode.TRACKING || cameraMode == CameraMode.TRACKING_COMPASS diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index 9118f926f3..e624378487 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -26,6 +26,8 @@ import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener; import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener; import com.mapbox.mapboxsdk.maps.MapboxMap.OnMapClickListener; +import org.jetbrains.annotations.NotNull; + import java.util.concurrent.CopyOnWriteArrayList; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; @@ -116,6 +118,11 @@ public final class LocationComponent { */ private boolean isLayerReady; + /** + * Indicates whether we are listening for compass updates. + */ + private boolean isListeningToCompass; + private StaleStateManager staleStateManager; private final CopyOnWriteArrayList<OnLocationStaleListener> onLocationStaleListeners = new CopyOnWriteArrayList<>(); @@ -135,6 +142,21 @@ public final class LocationComponent { this.mapboxMap = mapboxMap; } + public LocationComponent(@NotNull MapboxMap mapboxMap, @NotNull LocationEngine locationEngine, + @NotNull LocationLayerController locationLayerController, + @NotNull LocationCameraController locationCameraController, + @NotNull LocationAnimatorCoordinator locationAnimatorCoordinator, + @NotNull StaleStateManager staleStateManager, @NotNull CompassEngine compassEngine) { + this.mapboxMap = mapboxMap; + this.locationEngine = locationEngine; + this.locationLayerController = locationLayerController; + this.locationCameraController = locationCameraController; + this.locationAnimatorCoordinator = locationAnimatorCoordinator; + this.staleStateManager = staleStateManager; + this.compassEngine = compassEngine; + 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)}. @@ -276,6 +298,7 @@ public final class LocationComponent { locationCameraController.setCameraMode(cameraMode); boolean isGpsNorth = cameraMode == CameraMode.TRACKING_GPS_NORTH; locationAnimatorCoordinator.resetAllCameraAnimations(mapboxMap.getCameraPosition(), isGpsNorth); + updateCompassListenerState(true); } /** @@ -302,6 +325,7 @@ public final class LocationComponent { public void setRenderMode(@RenderMode.Mode int renderMode) { locationLayerController.setRenderMode(renderMode); updateLayerOffsets(true); + updateCompassListenerState(true); } /** @@ -345,6 +369,8 @@ public final class LocationComponent { staleStateManager.setEnabled(options.enableStaleState()); staleStateManager.setDelayTime(options.staleStateTimeout()); locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); + locationAnimatorCoordinator.setCompassAnimationEnabled(options.compassAnimationEnabled()); + locationAnimatorCoordinator.setAccuracyAnimationEnabled(options.accuracyAnimationEnabled()); updateMapWithOptions(options); } @@ -518,10 +544,12 @@ public final class LocationComponent { * * @param compassEngine to be used */ - public void setCompassEngine(@NonNull CompassEngine compassEngine) { - this.compassEngine.removeCompassListener(compassListener); + public void setCompassEngine(@Nullable CompassEngine compassEngine) { + if (this.compassEngine != null) { + updateCompassListenerState(false); + } this.compassEngine = compassEngine; - compassEngine.addCompassListener(compassListener); + updateCompassListenerState(true); } /** @@ -529,7 +557,7 @@ public final class LocationComponent { * * @return compass engine currently being used */ - @NonNull + @Nullable public CompassEngine getCompassEngine() { return compassEngine; } @@ -555,9 +583,11 @@ public final class LocationComponent { * The last known accuracy of the compass sensor, one of SensorManager.SENSOR_STATUS_* * * @return the last know compass accuracy bearing + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public float getLastKnownCompassAccuracyStatus() { - return compassEngine.getLastAccuracySensorStatus(); + return compassEngine != null ? compassEngine.getLastAccuracySensorStatus() : 0; } /** @@ -566,9 +596,13 @@ public final class LocationComponent { * * @param compassListener a {@link CompassListener} for listening into compass heading and * accuracy changes + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public void addCompassListener(@NonNull CompassListener compassListener) { - compassEngine.addCompassListener(compassListener); + if (compassEngine != null) { + compassEngine.addCompassListener(compassListener); + } } /** @@ -576,9 +610,13 @@ public final class LocationComponent { * * @param compassListener the {@link CompassListener} which you'd like to remove from the listener * list. + * @deprecated Use {@link #getCompassEngine()} */ + @Deprecated public void removeCompassListener(@NonNull CompassListener compassListener) { - compassEngine.removeCompassListener(compassListener); + if (compassEngine != null) { + compassEngine.removeCompassListener(compassListener); + } } /** @@ -714,7 +752,6 @@ public final class LocationComponent { if (options.enableStaleState()) { staleStateManager.onStart(); } - compassEngine.onStart(); } if (isEnabled) { @@ -726,6 +763,7 @@ public final class LocationComponent { } setCameraMode(locationCameraController.getCameraMode()); setLastLocation(); + updateCompassListenerState(true); setLastCompassHeading(); } } @@ -738,7 +776,9 @@ public final class LocationComponent { isLayerReady = false; locationLayerController.hide(); staleStateManager.onStop(); - compassEngine.onStop(); + if (compassEngine != null) { + updateCompassListenerState(false); + } locationAnimatorCoordinator.cancelAllAnimations(); if (locationEngine != null) { if (usingInternalLocationEngine) { @@ -768,15 +808,19 @@ public final class LocationComponent { locationCameraController = new LocationCameraController( context, mapboxMap, cameraTrackingChangedListener, options, onCameraMoveInvalidateListener); - locationAnimatorCoordinator = new LocationAnimatorCoordinator(); + locationAnimatorCoordinator = new LocationAnimatorCoordinator( + mapboxMap.getProjection(), + MapboxAnimatorSetProvider.getInstance() + ); locationAnimatorCoordinator.addLayerListener(locationLayerController); locationAnimatorCoordinator.addCameraListener(locationCameraController); locationAnimatorCoordinator.setTrackingAnimationDurationMultiplier(options.trackingAnimationDurationMultiplier()); WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); - compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); - compassEngine.addCompassListener(compassListener); + if (windowManager != null && sensorManager != null) { + compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); + } staleStateManager = new StaleStateManager(onLocationStaleListener, options); updateMapWithOptions(options); @@ -804,6 +848,38 @@ public final class LocationComponent { locationEngine.activate(); } + private void updateCompassListenerState(boolean canListen) { + if (compassEngine != null) { + if (!canListen) { + // We shouldn't listen, simply unregistering + removeCompassListener(compassEngine); + return; + } + + if (!isInitialized || !isComponentStarted || !isEnabled) { + return; + } + + if (locationCameraController.isConsumingCompass() || locationLayerController.isConsumingCompass()) { + // If we have a consumer, and not yet listening, then start listening + if (!isListeningToCompass) { + isListeningToCompass = true; + compassEngine.addCompassListener(compassListener); + } + } else { + // If we have no consumers, stop listening + removeCompassListener(compassEngine); + } + } + } + + private void removeCompassListener(@NonNull CompassEngine engine) { + if (isListeningToCompass) { + isListeningToCompass = false; + engine.removeCompassListener(compassListener); + } + } + private void enableLocationComponent() { isEnabled = true; onLocationLayerStart(); @@ -815,9 +891,12 @@ public final class LocationComponent { } private void updateMapWithOptions(final LocationComponentOptions options) { - mapboxMap.setPadding( - options.padding()[0], options.padding()[1], options.padding()[2], options.padding()[3] - ); + int[] padding = options.padding(); + if (padding != null) { + mapboxMap.setPadding( + padding[0], padding[1], padding[2], padding[3] + ); + } mapboxMap.setMaxZoomPreference(options.maxZoom()); mapboxMap.setMinZoomPreference(options.minZoom()); @@ -869,7 +948,7 @@ public final class LocationComponent { } private void setLastCompassHeading() { - updateCompassHeading(compassEngine.getLastHeading()); + updateCompassHeading(compassEngine != null ? compassEngine.getLastHeading() : 0); } @SuppressLint("MissingPermission") diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java index b53d909de3..6db307369a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java @@ -10,6 +10,8 @@ import android.support.annotation.Nullable; import android.view.Surface; import android.view.WindowManager; +import com.mapbox.mapboxsdk.log.Logger; + import java.util.ArrayList; import java.util.List; @@ -21,15 +23,18 @@ import timber.log.Timber; */ class LocationComponentCompassEngine implements CompassEngine, SensorEventListener { + private static final String TAG = "Mbgl-LocationComponentCompassEngine"; + // The rate sensor events will be delivered at. As the Android documentation states, this is only // a hint to the system and the events might actually be received faster or slower then this // specified rate. Since the minimum Android API levels about 9, we are able to set this value // ourselves rather than using one of the provided constants which deliver updates too quickly for // our use case. The default is set to 100ms - private static final int SENSOR_DELAY_MICROS = 100 * 1000; + static final int SENSOR_DELAY_MICROS = 100 * 1000; // Filtering coefficient 0 < ALPHA < 1 private static final float ALPHA = 0.45f; + @NonNull private final WindowManager windowManager; private final SensorManager sensorManager; private final List<CompassListener> compassListeners = new ArrayList<>(); @@ -56,7 +61,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen * Construct a new instance of the this class. A internal compass listeners needed to separate it * from the cleared list of public listeners. */ - LocationComponentCompassEngine(WindowManager windowManager, SensorManager sensorManager) { + LocationComponentCompassEngine(@NonNull WindowManager windowManager, @NonNull SensorManager sensorManager) { this.windowManager = windowManager; this.sensorManager = sensorManager; compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); @@ -75,7 +80,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @Override public void addCompassListener(@NonNull CompassListener compassListener) { if (compassListeners.isEmpty()) { - onStart(); + registerSensorListeners(); } compassListeners.add(compassListener); } @@ -84,7 +89,7 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen public void removeCompassListener(@NonNull CompassListener compassListener) { compassListeners.remove(compassListener); if (compassListeners.isEmpty()) { - onStop(); + unregisterSensorListeners(); } } @@ -100,12 +105,16 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen @Override public void onStart() { - registerSensorListeners(); + if (!compassListeners.isEmpty()) { + registerSensorListeners(); + } } @Override public void onStop() { - unregisterSensorListeners(); + if (!compassListeners.isEmpty()) { + unregisterSensorListeners(); + } } @Override @@ -116,15 +125,12 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen return; } if (lastAccuracySensorStatus == SensorManager.SENSOR_STATUS_UNRELIABLE) { - Timber.d("Compass sensor is unreliable, device calibration is needed."); + Logger.d(TAG, "Compass sensor is unreliable, device calibration is needed."); return; } if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { rotationVectorValue = getRotationVectorFromSensorEvent(event); updateOrientation(); - - // Update the compassUpdateNextTimestamp - compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { notifyCompassChangeListeners((event.values[0] + 360) % 360); } else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { @@ -134,6 +140,9 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen magneticValues = lowPassFilter(getRotationVectorFromSensorEvent(event), magneticValues); updateOrientation(); } + + // Update the compassUpdateNextTimestamp + compassUpdateNextTimestamp = currentTime + LocationComponentConstants.COMPASS_UPDATE_RATE_MS; } @Override @@ -233,7 +242,8 @@ class LocationComponentCompassEngine implements CompassEngine, SensorEventListen * @param smoothedValues array of float, that contains previous state * @return float filtered array of float */ - private float[] lowPassFilter(float[] newValues, float[] smoothedValues) { + @NonNull + private float[] lowPassFilter(@NonNull float[] newValues, @Nullable float[] smoothedValues) { if (smoothedValues == null) { return newValues; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index 4376ef4e60..135534460a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -6,7 +6,7 @@ package com.mapbox.mapboxsdk.location; final class LocationComponentConstants { // Controls the compass update rate in milliseconds - static final int COMPASS_UPDATE_RATE_MS = 500; + static final long COMPASS_UPDATE_RATE_MS = 500; // Sets the transition animation duration when switching camera modes. static final long TRANSITION_ANIMATION_DURATION_MS = 750; @@ -24,7 +24,7 @@ final class LocationComponentConstants { static final long DEFAULT_TRACKING_TILT_ANIM_DURATION = 1250; // Threshold value to perform immediate camera/layer position update. - static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 500_000; + static final double INSTANT_LOCATION_TRANSITION_THRESHOLD = 50_000; // Sources static final String LOCATION_SOURCE = "mapbox-location-source"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java index 10dfff8694..58b86c7b3a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java @@ -111,6 +111,8 @@ public class LocationComponentOptions implements Parcelable { private float trackingMultiFingerMoveThreshold; private String layerBelow; private float trackingAnimationDurationMultiplier; + private boolean compassAnimationEnabled; + private boolean accuracyAnimationEnabled; public LocationComponentOptions( float accuracyAlpha, @@ -144,7 +146,9 @@ public class LocationComponentOptions implements Parcelable { float trackingInitialMoveThreshold, float trackingMultiFingerMoveThreshold, String layerBelow, - float trackingAnimationDurationMultiplier) { + float trackingAnimationDurationMultiplier, + boolean compassAnimationEnabled, + boolean accuracyAnimationEnabled) { this.accuracyAlpha = accuracyAlpha; this.accuracyColor = accuracyColor; this.backgroundDrawableStale = backgroundDrawableStale; @@ -180,6 +184,8 @@ public class LocationComponentOptions implements Parcelable { this.trackingMultiFingerMoveThreshold = trackingMultiFingerMoveThreshold; this.layerBelow = layerBelow; this.trackingAnimationDurationMultiplier = trackingAnimationDurationMultiplier; + this.compassAnimationEnabled = compassAnimationEnabled; + this.accuracyAnimationEnabled = accuracyAnimationEnabled; } /** @@ -304,6 +310,14 @@ public class LocationComponentOptions implements Parcelable { ); builder.trackingAnimationDurationMultiplier(trackingAnimationDurationMultiplier); + builder.compassAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_compassAnimationEnabled, true + ); + + builder.accuracyAnimationEnabled = typedArray.getBoolean( + R.styleable.mapbox_LocationComponent_mapbox_accuracyAnimationEnabled, true + ); + typedArray.recycle(); return builder.build(); @@ -723,6 +737,26 @@ public class LocationComponentOptions implements Parcelable { return trackingAnimationDurationMultiplier; } + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public boolean compassAnimationEnabled() { + return compassAnimationEnabled; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public boolean accuracyAnimationEnabled() { + return accuracyAnimationEnabled; + } + + @NonNull @Override public String toString() { return "LocationComponentOptions{" @@ -882,6 +916,10 @@ public class LocationComponentOptions implements Parcelable { h$ ^= Float.floatToIntBits(trackingMultiFingerMoveThreshold); h$ *= 1000003; h$ ^= Float.floatToIntBits(trackingAnimationDurationMultiplier); + h$ *= 1000003; + h$ ^= compassAnimationEnabled ? 1231 : 1237; + h$ *= 1000003; + h$ ^= accuracyAnimationEnabled ? 1231 : 1237; return h$; } @@ -921,7 +959,9 @@ public class LocationComponentOptions implements Parcelable { in.readFloat(), in.readFloat(), in.readString(), - in.readFloat() + in.readFloat(), + in.readInt() == 1, + in.readInt() == 1 ); } @@ -1020,6 +1060,8 @@ public class LocationComponentOptions implements Parcelable { dest.writeFloat(trackingMultiFingerMoveThreshold()); dest.writeString(layerBelow()); dest.writeFloat(trackingAnimationDurationMultiplier); + dest.writeInt(compassAnimationEnabled() ? 1 : 0); + dest.writeInt(accuracyAnimationEnabled() ? 1 : 0); } @Override @@ -1084,6 +1126,8 @@ public class LocationComponentOptions implements Parcelable { private Float trackingMultiFingerMoveThreshold; private String layerBelow; private Float trackingAnimationDurationMultiplier; + private Boolean compassAnimationEnabled; + private Boolean accuracyAnimationEnabled; Builder() { } @@ -1121,6 +1165,8 @@ public class LocationComponentOptions implements Parcelable { this.trackingMultiFingerMoveThreshold = source.trackingMultiFingerMoveThreshold(); this.layerBelow = source.layerBelow(); this.trackingAnimationDurationMultiplier = source.trackingAnimationDurationMultiplier(); + this.compassAnimationEnabled = source.compassAnimationEnabled(); + this.accuracyAnimationEnabled = source.accuracyAnimationEnabled(); } /** @@ -1556,6 +1602,28 @@ public class LocationComponentOptions implements Parcelable { return this; } + /** + * Enable or disable smooth animation of compass values for {@link com.mapbox.mapboxsdk.location.modes.CameraMode} + * and {@link com.mapbox.mapboxsdk.location.modes.RenderMode}. + * + * @return whether smooth compass animation is enabled + */ + public LocationComponentOptions.Builder compassAnimationEnabled(Boolean compassAnimationEnabled) { + this.compassAnimationEnabled = compassAnimationEnabled; + return this; + } + + /** + * Enable or disable smooth animation of the accuracy circle around the user's position. + * + * @return whether smooth animation of the accuracy circle is enabled + */ + public Builder accuracyAnimationEnabled(Boolean accuracyAnimationEnabled) { + this.accuracyAnimationEnabled = accuracyAnimationEnabled; + return this; + } + + @Nullable LocationComponentOptions autoBuild() { String missing = ""; if (this.accuracyAlpha == null) { @@ -1653,7 +1721,9 @@ public class LocationComponentOptions implements Parcelable { this.trackingInitialMoveThreshold, this.trackingMultiFingerMoveThreshold, this.layerBelow, - this.trackingAnimationDurationMultiplier); + this.trackingAnimationDurationMultiplier, + this.compassAnimationEnabled, + this.accuracyAnimationEnabled); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index da3144eea1..fc4dd1d872 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -11,8 +11,8 @@ import com.google.gson.JsonObject; import com.mapbox.geojson.Feature; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; @@ -192,6 +192,10 @@ final class LocationLayerController implements MapboxAnimator.OnLayerAnimationsV return isHidden; } + boolean isConsumingCompass() { + return renderMode == RenderMode.COMPASS; + } + private void setLayerVisibility(String layerId, boolean visible) { Layer layer = mapboxMap.getLayer(layerId); if (layer != null) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java new file mode 100644 index 0000000000..1d09f8ae71 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java @@ -0,0 +1,32 @@ +package com.mapbox.mapboxsdk.location; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.support.annotation.NonNull; +import android.view.animation.Interpolator; + +import java.util.List; + +class MapboxAnimatorSetProvider { + private static MapboxAnimatorSetProvider instance; + + private MapboxAnimatorSetProvider() { + // private constructor + } + + static MapboxAnimatorSetProvider getInstance() { + if (instance == null) { + instance = new MapboxAnimatorSetProvider(); + } + return instance; + } + + void startAnimation(@NonNull List<Animator> animators, @NonNull Interpolator interpolator, + long duration) { + AnimatorSet locationAnimatorSet = new AnimatorSet(); + locationAnimatorSet.playTogether(animators); + locationAnimatorSet.setInterpolator(interpolator); + locationAnimatorSet.setDuration(duration); + locationAnimatorSet.start(); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java index 553678709e..45911a99b3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java @@ -14,7 +14,11 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Projection; + +import static com.mapbox.mapboxsdk.location.LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD; public final class Utils { @@ -88,6 +92,12 @@ public final class Utils { return (float) (location.getAccuracy() * (1 / metersPerPixel)); } + static boolean immediateAnimation(@NonNull Projection projection, @NonNull LatLng current, @NonNull LatLng target) { + double metersPerPixel = projection.getMetersPerPixelAtLatitude((current.getLatitude() + target.getLatitude()) / 2); + double distance = current.distanceTo(target); + return distance / metersPerPixel > INSTANT_LOCATION_TRANSITION_THRESHOLD; + } + /** * Casts the value to an even integer. */ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java index 3eaa381239..69ae499a31 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java @@ -27,6 +27,8 @@ class MapChangeReceiver implements NativeMapView.StateCallback { = new CopyOnWriteArrayList<>(); private final List<MapView.OnDidFinishRenderingMapListener> onDidFinishRenderingMapListenerList = new CopyOnWriteArrayList<>(); + private final List<MapView.OnDidBecomeIdleListener> onDidBecomeIdleListenerList + = new CopyOnWriteArrayList<>(); private final List<MapView.OnDidFinishLoadingStyleListener> onDidFinishLoadingStyleListenerList = new CopyOnWriteArrayList<>(); private final List<MapView.OnSourceChangedListener> onSourceChangedListenerList = new CopyOnWriteArrayList<>(); @@ -172,6 +174,20 @@ class MapChangeReceiver implements NativeMapView.StateCallback { } @Override + public void onDidBecomeIdle() { + try { + if (!onDidBecomeIdleListenerList.isEmpty()) { + for (MapView.OnDidBecomeIdleListener listener : onDidBecomeIdleListenerList) { + listener.onDidBecomeIdle(); + } + } + } catch (Throwable err) { + Logger.e(TAG, "Exception in onDidBecomeIdle", err); + throw err; + } + } + + @Override public void onDidFinishLoadingStyle() { try { if (!onDidFinishLoadingStyleListenerList.isEmpty()) { @@ -279,6 +295,14 @@ class MapChangeReceiver implements NativeMapView.StateCallback { onDidFinishRenderingMapListenerList.remove(listener); } + void addOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) { + onDidBecomeIdleListenerList.add(listener); + } + + void removeOnDidBecomeIdleListener(MapView.OnDidBecomeIdleListener listener) { + onDidBecomeIdleListenerList.remove(listener); + } + void addOnDidFinishLoadingStyleListener(MapView.OnDidFinishLoadingStyleListener listener) { onDidFinishLoadingStyleListenerList.add(listener); } @@ -306,6 +330,7 @@ class MapChangeReceiver implements NativeMapView.StateCallback { onDidFinishRenderingFrameList.clear(); onWillStartRenderingMapListenerList.clear(); onDidFinishRenderingMapListenerList.clear(); + onDidBecomeIdleListenerList.clear(); onDidFinishLoadingStyleListenerList.clear(); onSourceChangedListenerList.clear(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 1997375f9e..0fe1e27662 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -96,6 +96,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { private MapKeyListener mapKeyListener; private MapZoomButtonController mapZoomButtonController; private Bundle savedInstanceState; + private boolean isActivated; @UiThread public MapView(@NonNull Context context) { @@ -371,8 +372,11 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { */ @UiThread public void onStart() { - ConnectivityReceiver.instance(getContext()).activate(); - FileSource.getInstance(getContext()).activate(); + if (!isActivated) { + ConnectivityReceiver.instance(getContext()).activate(); + FileSource.getInstance(getContext()).activate(); + isActivated = true; + } if (mapboxMap != null) { mapboxMap.onStart(); } @@ -417,8 +421,11 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { mapRenderer.onStop(); } - ConnectivityReceiver.instance(getContext()).deactivate(); - FileSource.getInstance(getContext()).deactivate(); + if (isActivated) { + ConnectivityReceiver.instance(getContext()).deactivate(); + FileSource.getInstance(getContext()).deactivate(); + isActivated = false; + } } /** @@ -851,13 +858,33 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { /** * Remove a callback that's invoked when the map has finished rendering. * - * @param listener The callback that's invoked when the map has finished rendering + * @param listener The callback that's invoked when the map has has finished rendering. */ public void removeOnDidFinishRenderingMapListener(OnDidFinishRenderingMapListener listener) { mapChangeReceiver.removeOnDidFinishRenderingMapListener(listener); } /** + * Set a callback that's invoked when the map has entered the idle state. + * + * @param listener The callback that's invoked when the map has entered the idle state. + */ + public void addOnDidBecomeIdleListener(OnDidBecomeIdleListener listener) { + mapChangeReceiver.addOnDidBecomeIdleListener(listener); + } + + /** + * Remove a callback that's invoked when the map has entered the idle state. + * + * @param listener The callback that's invoked when the map has entered the idle state. + */ + public void removeOnDidBecomeIdleListener(OnDidBecomeIdleListener listener) { + mapChangeReceiver.removeOnDidBecomeIdleListener(listener); + } + + /** + + /** * Set a callback that's invoked when the style has finished loading. * * @param listener The callback that's invoked when the style has finished loading @@ -1031,6 +1058,19 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { } /** + * Interface definition for a callback to be invoked when the map has entered the idle state. + * <p> + * {@link MapView#addOnDidBecomeIdleListener(OnDidBecomeIdleListener)} + * </p> + */ + public interface OnDidBecomeIdleListener { + /** + * Called when the map has entered the idle state. + */ + void onDidBecomeIdle(); + } + + /** * Interface definition for a callback to be invoked when the map has loaded the style. * <p> * {@link MapView#addOnDidFailLoadingMapListener(OnDidFailLoadingMapListener)} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 48c571ee98..7734e619f1 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -993,6 +993,11 @@ final class NativeMapView { } @Keep + private void onDidBecomeIdle() { + stateCallback.onDidBecomeIdle(); + } + + @Keep private void onDidFinishLoadingStyle() { stateCallback.onDidFinishLoadingStyle(); // deprecated API @@ -1445,6 +1450,8 @@ final class NativeMapView { void onDidFinishLoadingStyle(); + void onDidBecomeIdle(); + void onSourceChanged(String sourceId); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 970a7fc3b4..f284a636e6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -13,6 +13,7 @@ import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v4.content.res.ResourcesCompat; import android.text.Html; +import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; @@ -97,6 +98,7 @@ public class MapSnapshotter { private CameraPosition cameraPosition; private boolean showLogo = true; private String localIdeographFontFamily; + private String apiBaseUrl; /** * @param width the width of the image @@ -184,6 +186,18 @@ public class MapSnapshotter { } /** + * Specifies the URL used for API endpoint. + * + * @param apiBaseUrl The base of our API endpoint + * @return the mutated {@link Options} + */ + @NonNull + public Options withApiBaseUrl(String apiBaseUrl) { + this.apiBaseUrl = apiBaseUrl; + return this; + } + + /** * @return the width of the image */ public int getWidth() { @@ -234,6 +248,13 @@ public class MapSnapshotter { return localIdeographFontFamily; } + /** + * @return The base of our API endpoint + */ + @Nullable + public String getApiBaseUrl() { + return apiBaseUrl; + } } /** @@ -251,6 +272,11 @@ public class MapSnapshotter { telemetry.onAppUserTurnstileEvent(); } FileSource fileSource = FileSource.getInstance(context); + String apiBaseUrl = options.getApiBaseUrl(); + if (!TextUtils.isEmpty(apiBaseUrl)) { + fileSource.setApiBaseUrl(apiBaseUrl); + } + String programCacheDir = FileSource.getInternalCachePath(context); nativeInitialize(this, fileSource, options.pixelRatio, options.width, diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java index f180eda809..122349328f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java @@ -14,6 +14,7 @@ import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.exceptions.ConversionException; import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -147,7 +148,10 @@ public class ColorUtils { * @return String rgba color */ public static String colorToRgbaString(@ColorInt int color) { - String alpha = new DecimalFormat("#.###").format(((float) ((color >> 24) & 0xFF)) / 255.0f); + NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US); + DecimalFormat decimalFormat = (DecimalFormat) numberFormat; + decimalFormat.applyPattern("#.###"); + String alpha = decimalFormat.format(((float) ((color >> 24) & 0xFF)) / 255.0f); return String.format(Locale.US, "rgba(%d, %d, %d, %s)", (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, alpha); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 730ab580d0..4e9d1c5d8d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -152,4 +152,10 @@ <!-- Animation duration multiplier --> <public name="mapbox_trackingAnimationDurationMultiplier" format="float" type="attr" /> + + <!-- Compass animation --> + <public name="mapbox_compassAnimationEnabled" format="boolean" type="attr" /> + + <!-- Accuracy animation--> + <public name="mapbox_accuracyAnimationEnabled" format="boolean" type="attr" /> </resources> diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index 9f0ca86a86..ed2dbe01df 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -178,5 +178,11 @@ <!-- Animation duration multiplier --> <attr name="mapbox_trackingAnimationDurationMultiplier" format="float" /> + <!-- Compass animation --> + <attr name="mapbox_compassAnimationEnabled" format="boolean" /> + + <!-- Accuracy animation--> + <attr name="mapbox_accuracyAnimationEnabled" format="boolean" /> + </declare-styleable> </resources> diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java index bc64379263..bebd828118 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.location; import android.hardware.Sensor; +import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.view.WindowManager; @@ -10,7 +11,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import static com.mapbox.mapboxsdk.location.LocationComponentCompassEngine.SENSOR_DELAY_MICROS; import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -27,8 +31,15 @@ public class CompassEngineTest { @Mock private SensorManager sensorManager; + @Mock + private Sensor compassSensor; + + @Mock + private CompassListener compassListener; + @Before public void setUp() throws Exception { + when(sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)).thenReturn(compassSensor); compassEngine = new LocationComponentCompassEngine(windowManager, sensorManager); } @@ -61,4 +72,18 @@ public class CompassEngineTest { verify(sensorManager, times(1)).getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); } + + @Test + public void listener_registerOnAdd() { + compassEngine.addCompassListener(compassListener); + verify(sensorManager) + .registerListener(any(SensorEventListener.class), eq(compassSensor), eq(SENSOR_DELAY_MICROS)); + } + + @Test + public void listener_unregisterOnRemove() { + compassEngine.addCompassListener(compassListener); + compassEngine.removeCompassListener(compassListener); + verify(sensorManager).unregisterListener(any(SensorEventListener.class), eq(compassSensor)); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt index 2c94642610..7c75a8cb75 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt @@ -1,17 +1,24 @@ package com.mapbox.mapboxsdk.location +import android.animation.Animator import android.location.Location +import android.view.animation.LinearInterpolator import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_TILT_ANIM_DURATION import com.mapbox.mapboxsdk.location.LocationComponentConstants.DEFAULT_TRACKING_ZOOM_ANIM_DURATION import com.mapbox.mapboxsdk.location.MapboxAnimator.* +import com.mapbox.mapboxsdk.maps.Projection import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) @@ -20,9 +27,12 @@ class LocationAnimatorCoordinatorTest { private lateinit var locationAnimatorCoordinator: LocationAnimatorCoordinator private val cameraPosition: CameraPosition = CameraPosition.DEFAULT + private lateinit var animatorSetProvider: MapboxAnimatorSetProvider + @Before fun setUp() { - locationAnimatorCoordinator = LocationAnimatorCoordinator() + animatorSetProvider = mock(MapboxAnimatorSetProvider::class.java) + locationAnimatorCoordinator = LocationAnimatorCoordinator(mock(Projection::class.java), animatorSetProvider) } @Test @@ -125,9 +135,6 @@ class LocationAnimatorCoordinatorTest { val layerAccuracy = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.target as Float assertEquals(layerAccuracy, accuracy) - - val animationDuration = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.duration as Long - assertEquals(LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION, animationDuration) } @Test @@ -144,9 +151,6 @@ class LocationAnimatorCoordinatorTest { val layerAccuracy = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.target as Float assertEquals(layerAccuracy, accuracy) - - val animationDuration = locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]?.duration as Long - assertEquals(0L, animationDuration) } @Test @@ -281,4 +285,50 @@ class LocationAnimatorCoordinatorTest { assertTrue(locationAnimatorCoordinator.cameraListeners.isEmpty()) } + + @Test + fun feedNewCompassBearing_withAnimation() { + locationAnimatorCoordinator.setCompassAnimationEnabled(true) + locationAnimatorCoordinator.feedNewCompassBearing(77f, cameraPosition) + + val animators = mutableListOf<Animator>( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING]) + + verify(animatorSetProvider).startAnimation(eq(animators), any(LinearInterpolator::class.java), eq(LocationComponentConstants.COMPASS_UPDATE_RATE_MS)) + } + + @Test + fun feedNewCompassBearing_withoutAnimation() { + locationAnimatorCoordinator.setCompassAnimationEnabled(false) + locationAnimatorCoordinator.feedNewCompassBearing(77f, cameraPosition) + + val animators = mutableListOf<Animator>( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_COMPASS_BEARING], + locationAnimatorCoordinator.animatorArray[ANIMATOR_CAMERA_COMPASS_BEARING]) + + verify(animatorSetProvider).startAnimation(eq(animators), any(LinearInterpolator::class.java), eq(0L)) + } + + @Test + fun feedNewAccuracy_withAnimation() { + locationAnimatorCoordinator.setAccuracyAnimationEnabled(true) + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, false) + + val animators = mutableListOf<Animator>( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]) + + verify(animatorSetProvider).startAnimation(eq(animators), any(LinearInterpolator::class.java), eq(LocationComponentConstants.ACCURACY_RADIUS_ANIMATION_DURATION)) + } + + @Test + fun feedNewAccuracy_withoutAnimation() { + locationAnimatorCoordinator.setAccuracyAnimationEnabled(false) + locationAnimatorCoordinator.feedNewAccuracyRadius(150f, false) + + val animators = mutableListOf<Animator>( + locationAnimatorCoordinator.animatorArray[ANIMATOR_LAYER_ACCURACY]) + + verify(animatorSetProvider).startAnimation(eq(animators), any(LinearInterpolator::class.java), eq(0L)) + } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java index 9e26bb1a60..da2773c592 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java @@ -416,6 +416,9 @@ public class LocationCameraControllerTest { private LocationCameraController buildCamera(OnCameraTrackingChangedListener onCameraTrackingChangedListener) { MapboxMap mapboxMap = mock(MapboxMap.class); when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); MoveGestureDetector moveGestureDetector = mock(MoveGestureDetector.class); OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); @@ -427,6 +430,9 @@ public class LocationCameraControllerTest { private LocationCameraController buildCamera(MoveGestureDetector moveGestureDetector) { MapboxMap mapboxMap = mock(MapboxMap.class); when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); + Projection projection = mock(Projection.class); + when(mapboxMap.getProjection()).thenReturn(projection); + when(projection.getMetersPerPixelAtLatitude(any(Double.class))).thenReturn(Double.valueOf(1000)); OnCameraTrackingChangedListener onCameraTrackingChangedListener = mock(OnCameraTrackingChangedListener.class); OnCameraMoveInvalidateListener onCameraMoveInvalidateListener = mock(OnCameraMoveInvalidateListener.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt new file mode 100644 index 0000000000..5879b8184f --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -0,0 +1,214 @@ +package com.mapbox.mapboxsdk.location + +import android.content.Context +import com.mapbox.android.core.location.LocationEngine +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.location.modes.CameraMode +import com.mapbox.mapboxsdk.location.modes.RenderMode +import com.mapbox.mapboxsdk.maps.MapboxMap +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 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 + + @Before + fun before() { + MockitoAnnotations.initMocks(this) + locationComponent = LocationComponent(mapboxMap, locationEngine, locationLayerController, + locationCameraController, locationAnimatorCoordinator, staleStateManager, compassEngine) + } + + @Test + fun compass_listenWhenConsumedByNoneCamera() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationCameraController.isConsumingCompass).thenReturn(true) + locationComponent.cameraMode = CameraMode.NONE_COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_listenWhenConsumedByTrackingCamera() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationCameraController.isConsumingCompass).thenReturn(true) + locationComponent.cameraMode = CameraMode.TRACKING_COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_listenWhenConsumedByLayer() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notListenWhenNotConsumed() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(false) + `when`(locationCameraController.isConsumingCompass).thenReturn(false) + locationComponent.renderMode = RenderMode.GPS + locationComponent.renderMode = RenderMode.NORMAL + locationComponent.cameraMode = CameraMode.TRACKING + locationComponent.cameraMode = CameraMode.NONE + locationComponent.cameraMode = CameraMode.NONE_GPS + locationComponent.cameraMode = CameraMode.TRACKING_GPS + locationComponent.cameraMode = CameraMode.TRACKING_GPS_NORTH + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnChange() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + `when`(locationLayerController.isConsumingCompass).thenReturn(false) + locationComponent.renderMode = RenderMode.NORMAL + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnStop() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStop() + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnStart() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStop() + locationComponent.onStart() + verify(compassEngine, times(2)).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_removeListenerOnStyleStartLoad() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStartLoadingMap() + verify(compassEngine).removeCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnStyleLoadFinished() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.onStartLoadingMap() + locationComponent.onFinishLoadingStyle() + verify(compassEngine, times(2)).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_reAddListenerOnlyWhenEnabled() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + locationComponent.isLocationComponentEnabled = false + locationComponent.onStartLoadingMap() + locationComponent.onFinishLoadingStyle() + verify(compassEngine).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notAdListenerWhenDisabled() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.onStart() + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } + + @Test + fun compass_notAdListenerWhenStopped() { + locationComponent.activateLocationComponent(context, locationEngine, locationComponentOptions) + locationComponent.isLocationComponentEnabled = true + `when`(mapboxMap.cameraPosition).thenReturn(CameraPosition.DEFAULT) + + `when`(locationLayerController.isConsumingCompass).thenReturn(true) + locationComponent.renderMode = RenderMode.COMPASS + verify(compassEngine, never()).addCompassListener(any(CompassListener::class.java)) + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java index 688b4badec..913c47fcd6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java @@ -1,8 +1,10 @@ package com.mapbox.mapboxsdk.maps; +import com.google.common.util.concurrent.ExecutionError; import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.log.LoggerDefinition; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -53,6 +55,9 @@ public class MapChangeReceiverTest { private MapView.OnDidFinishRenderingMapListener onDidFinishRenderingMapListener; @Mock + private MapView.OnDidBecomeIdleListener onDidBecomeIdleListener; + + @Mock private MapView.OnDidFinishLoadingStyleListener onDidFinishLoadingStyleListener; @Mock @@ -307,6 +312,36 @@ public class MapChangeReceiverTest { } @Test + public void testOnDidBecomeIdleListener() { + mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener); + mapChangeEventManager.onDidBecomeIdle(); + verify(onDidBecomeIdleListener).onDidBecomeIdle(); + mapChangeEventManager.removeOnDidBecomeIdleListener(onDidBecomeIdleListener); + mapChangeEventManager.onDidBecomeIdle(); + verify(onDidBecomeIdleListener).onDidBecomeIdle(); + + mapChangeEventManager.addOnDidBecomeIdleListener(onDidBecomeIdleListener); + Logger.setLoggerDefinition(loggerDefinition); + Exception exc = new RuntimeException(); + doThrow(exc).when(onDidBecomeIdleListener).onDidBecomeIdle(); + try { + mapChangeEventManager.onDidBecomeIdle(); + Assert.fail("The exception should've been re-thrown."); + } catch (RuntimeException throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(exc)); + } + + Error err = new ExecutionError("", new Error()); + doThrow(err).when(onDidBecomeIdleListener).onDidBecomeIdle(); + try { + mapChangeEventManager.onDidBecomeIdle(); + Assert.fail("The exception should've been re-thrown."); + } catch (ExecutionError throwable) { + verify(loggerDefinition).e(anyString(), anyString(), eq(err)); + } + } + + @Test public void testOnDidFinishLoadingStyleListener() { mapChangeEventManager.addOnDidFinishLoadingStyleListener(onDidFinishLoadingStyleListener); mapChangeEventManager.onDidFinishLoadingStyle(); |