summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkevin <kevin.li@mapbox.com>2019-01-16 08:29:58 -0800
committerkevin <kevin.li@mapbox.com>2019-01-16 08:29:58 -0800
commitc09831cda04bf97c1c208cacfaaa660c36003cbd (patch)
treee1ff23c5feaea81d0e6ec096b17e5f223204c2d4
parent788158cc5608bc428b13ad0ef6215626e1acaffd (diff)
parentb23a6122259cac97f174dddb978437dd3a58a5df (diff)
downloadqtlocation-mapboxgl-upstream/no-v7.tar.gz
Merge branch 'release-horchata' into no-v7upstream/no-v7
-rw-r--r--appveyor.yml4
-rw-r--r--include/mbgl/map/map_observer.hpp1
-rw-r--r--package.json2
-rw-r--r--platform/android/CHANGELOG.md32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassEngine.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/CompassListener.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinator.java59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java111
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentCompassEngine.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java76
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/MapboxAnimatorSetProvider.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/Utils.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapChangeReceiver.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java50
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/CompassEngineTest.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationAnimatorCoordinatorTest.kt64
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt214
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapChangeReceiverTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt148
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml1
-rw-r--r--platform/android/gradle/dependencies.gradle2
-rw-r--r--platform/android/gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xplatform/android/src/native_map_view.cpp9
-rwxr-xr-xplatform/android/src/native_map_view.hpp1
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h13
-rw-r--r--platform/ios/test/MGLMapViewDelegateIntegrationTests.swift2
-rw-r--r--platform/macos/src/MGLMapView.mm14
-rw-r--r--platform/macos/src/MGLMapViewDelegate.h13
-rw-r--r--platform/macos/test/MGLMapViewDelegateIntegrationTests.swift2
-rw-r--r--scripts/changelog_staging/idle-event.json6
-rw-r--r--src/mbgl/map/map.cpp2
52 files changed, 1058 insertions, 94 deletions
diff --git a/appveyor.yml b/appveyor.yml
index b1fe0b9f4f..53970e1ac5 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -47,8 +47,8 @@ for:
- image: Visual Studio 2017
environment:
- LLVM_VERSION: 6.0.0
- LLVM_HASH: 2501887b2f638d3f65b0336f354b96f8108b563522d81e841d5c88c34af283dd
+ LLVM_VERSION: 7.0.0
+ LLVM_HASH: 74b197a3959b0408adf0824be01db8dddfa2f9a967f4085af3fad900ed5fdbf6
VCVARSALL: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat'
QT_PREFIX: 'C:\Qt\latest\msvc2017_64\lib\cmake'
diff --git a/include/mbgl/map/map_observer.hpp b/include/mbgl/map/map_observer.hpp
index f63e5f2af3..98b218f8f0 100644
--- a/include/mbgl/map/map_observer.hpp
+++ b/include/mbgl/map/map_observer.hpp
@@ -39,6 +39,7 @@ public:
virtual void onDidFinishRenderingMap(RenderMode) {}
virtual void onDidFinishLoadingStyle() {}
virtual void onSourceChanged(style::Source&) {}
+ virtual void onDidBecomeIdle() {}
};
} // namespace mbgl
diff --git a/package.json b/package.json
index 7ddbad1997..ec8556c5ea 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
},
"license": "BSD-2-Clause",
"dependencies": {
- "@mapbox/cmake-node-module": "^1.1.0",
+ "@mapbox/cmake-node-module": "1.1.0",
"node-pre-gyp": "^0.10.2",
"npm-run-all": "^4.0.2"
},
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 743916dad9..a9a8c7606c 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -3,7 +3,37 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## master
-- Add `fill-extrusion-vertical-gradient` fill paint property [#13463](https://github.com/mapbox/mapbox-gl-native/pull/13463)
+
+## 6.8.0 - December 19, 2018
+ - Update core styles based on the streets-v8 source. This results in breaking changes for any code that references internal layers and sources of the style [#13615](https://github.com/mapbox/mapbox-gl-native/pull/13615)
+ - Fixed compass update time not getting updated [#13569](https://github.com/mapbox/mapbox-gl-native/pull/13569)
+ - Register compass sensor listener only if necessary [#13573](https://github.com/mapbox/mapbox-gl-native/pull/13573)
+ - Immediate location animation based on map's projection [#13545](https://github.com/mapbox/mapbox-gl-native/pull/13545)
+ - Option to disable smooth animation of compass and accuracy values [#13574](https://github.com/mapbox/mapbox-gl-native/pull/13574)
+ - Add onDidBecomeIdle to Map events [#13513](https://github.com/mapbox/mapbox-gl-native/pull/13513)
+ - Expose setAccessToken on Mapbox.java [#13397](https://github.com/mapbox/mapbox-gl-native/pull/13397)
+ - Use locale sensitive DecimalFormat for color alpha conversion [#13393](https://github.com/mapbox/mapbox-gl-native/pull/13393)
+ - Enabled RecyclerView integration [#13132](https://github.com/mapbox/mapbox-gl-native/pull/13132)
+
+## 7.0.0-beta.1 - December 12, 2018
+ - Style builder and Style.java [#13484](https://github.com/mapbox/mapbox-gl-native/pull/13484)
+ - LatLng bounds cannot be wrapped [#13419](https://github.com/mapbox/mapbox-gl-native/pull/13419)
+ - Expose endpoint change option for snapshotter [#13508](https://github.com/mapbox/mapbox-gl-native/pull/13508)
+ - Formatted "text-field" property setter [#13358](https://github.com/mapbox/mapbox-gl-native/pull/13358)
+ - Expose setAccesToken on Mapbox.java [#13397](https://github.com/mapbox/mapbox-gl-native/pull/13397)
+ - Immediately notify core about forced connectivity state [#13485](https://github.com/mapbox/mapbox-gl-native/pull/13485)
+ - Handle transition duration of 0ms for symbols [#13535](https://github.com/mapbox/mapbox-gl-native/pull/13535)
+ - Returning boolean when removing sources and layers [#13428](https://github.com/mapbox/mapbox-gl-native/pull/13428)
+ - Telemetry v4.1.1 bump [#13499](https://github.com/mapbox/mapbox-gl-native/pull/13499)
+ - mapbox-java 4.2.0 bump [#13507](https://github.com/mapbox/mapbox-gl-native/pull/13507)
+
+## 7.0.0-alpha.3 - November 30, 2018
+ - Add `fill-extrusion-vertical-gradient` fill paint property [#13463](https://github.com/mapbox/mapbox-gl-native/pull/13463)
+ - Don't cancel core transitions on MotionEvent#ACTION_CANCEL [#13465](https://github.com/mapbox/mapbox-gl-native/pull/13465)
+ - Require context in AttributionParser.Options [#13444](https://github.com/mapbox/mapbox-gl-native/pull/13444)
+ - Deprecated annotations package [#13468](https://github.com/mapbox/mapbox-gl-native/pull/13468)
+ - Send turnstile event while create MapSnapshotter instance [#13475](https://github.com/mapbox/mapbox-gl-native/pull/13475)
+ - Remove default zoom level restrictions when activating the location component [#13425](https://github.com/mapbox/mapbox-gl-native/pull/13425)
## 6.7.2 - November 30, 2018
- Telemetry v3.5.6 [#13486](https://github.com/mapbox/mapbox-gl-native/pull/13486)
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();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
index 444b478219..41e67ca31b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
@@ -1106,12 +1106,15 @@ class LocationComponentTest : BaseActivityTest() {
uiController: UiController, context: Context) {
component.activateLocationComponent(context, false)
component.isLocationComponentEnabled = true
- val target = LatLng(51.0, 17.0)
- assertTrue(target.distanceTo(LatLng(location)) > LocationComponentConstants.INSTANT_LOCATION_TRANSITION_THRESHOLD)
component.cameraMode = CameraMode.NONE
component.forceLocationUpdate(location)
+
+ val target = LatLng(51.0, 17.0)
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(target))
+ mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(15.0))
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0))
+ assertTrue(Utils.immediateAnimation(mapboxMap.projection, mapboxMap.cameraPosition.target, LatLng(location)))
+
component.cameraMode = CameraMode.TRACKING_GPS
assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1)
assertEquals(location.latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
index 3648aaeebe..7c84a92ae0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
@@ -6,10 +6,14 @@ import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
import org.junit.Test;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
public class MapboxTest extends BaseActivityTest {
+ private static final String ACCESS_TOKEN = "pk.0000000001";
+ private static final String ACCESS_TOKEN_2 = "pk.0000000002";
+
@Override
protected Class getActivityClass() {
return EspressoTestActivity.class;
@@ -30,4 +34,15 @@ public class MapboxTest extends BaseActivityTest {
Mapbox.setConnected(null);
assertTrue(Mapbox.isConnected());
}
+
+ @Test
+ public void setAccessToken() {
+ validateTestSetup();
+ String realToken = Mapbox.getAccessToken();
+ Mapbox.setAccessToken(ACCESS_TOKEN);
+ assertSame(ACCESS_TOKEN, Mapbox.getAccessToken());
+ Mapbox.setAccessToken(ACCESS_TOKEN_2);
+ assertSame(ACCESS_TOKEN_2, Mapbox.getAccessToken());
+ Mapbox.setAccessToken(realToken);
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 14066123d3..1ec0116047 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -873,6 +873,17 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
+ <activity
+ android:name=".activity.maplayout.RecyclerViewActivity"
+ android:description="@string/description_recyclerview"
+ android:label="@string/activity_recyclerview">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_maplayout" />
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
+ </activity>
<!-- For Instrumentation tests -->
<activity
android:name=".activity.style.RuntimeStyleTestActivity"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java
index e3af101a8d..c7d45a879a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapChangeActivity.java
@@ -33,6 +33,7 @@ public class MapChangeActivity extends AppCompatActivity {
mapView.addOnDidFinishLoadingStyleListener(() -> Timber.v("OnDidFinishLoadingStyle"));
mapView.addOnDidFinishRenderingFrameListener(fully -> Timber.v("OnDidFinishRenderingFrame: fully: %s", fully));
mapView.addOnDidFinishRenderingMapListener(fully -> Timber.v("OnDidFinishRenderingMap: fully: %s", fully));
+ mapView.addOnDidBecomeIdleListener(() -> Timber.v("OnDidBecomeIdle"));
mapView.addOnSourceChangedListener(sourceId -> Timber.v("OnSourceChangedListener: source with id: %s", sourceId));
mapView.addOnWillStartLoadingMapListener(() -> Timber.v("OnWillStartLoadingMap"));
mapView.addOnWillStartRenderingFrameListener(() -> Timber.v("OnWillStartRenderingFrame"));
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt
new file mode 100644
index 0000000000..d35c977df0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt
@@ -0,0 +1,148 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.TextView
+import com.mapbox.mapboxsdk.maps.MapView
+import com.mapbox.mapboxsdk.testapp.R
+import kotlinx.android.synthetic.main.activity_recyclerview.*
+
+/**
+ * TestActivity showcasing how to integrate a MapView in a RecyclerView.
+ * <p>
+ * It requires calling the correct lifecycle methods when detaching and attaching the View to
+ * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
+ * </p>
+ */
+@SuppressLint("ClickableViewAccessibility")
+class RecyclerViewActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_recyclerview)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = ItemAdapter(LayoutInflater.from(this), savedInstanceState)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle?) {
+ super.onSaveInstanceState(outState)
+ // to save state, we need to call MapView#onSaveInstanceState
+ (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState)
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ // to release memory, we need to call MapView#onLowMemory
+ (recyclerView.adapter as ItemAdapter).onLowMemory()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ // to perform cleanup, we need to call MapView#onDestroy
+ (recyclerView.adapter as ItemAdapter).onDestroy()
+ }
+
+ class ItemAdapter(private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+
+ private val items = listOf(
+ "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
+ "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+ "nineteen", "twenty", "twenty-one"
+ )
+
+ private var mapHolder: MapHolder? = null
+
+ companion object {
+ const val TYPE_MAP = 0
+ const val TYPE_TEXT = 1
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return if (viewType == TYPE_MAP) {
+ val mapView = inflater.inflate(R.layout.item_map, parent, false) as MapView
+ mapHolder = MapHolder(mapView, savedInstanceState)
+ return mapHolder as MapHolder
+ } else {
+ TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
+ }
+ }
+
+ override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
+ super.onViewAttachedToWindow(holder)
+ if (holder is MapHolder) {
+ val mapView = holder.mapView
+ mapView.onStart()
+ mapView.onResume()
+ }
+ }
+
+ override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
+ super.onViewDetachedFromWindow(holder)
+ if (holder is MapHolder) {
+ val mapView = holder.mapView
+ mapView.onPause()
+ mapView.onStop()
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return items.count()
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder.itemViewType == TYPE_TEXT) {
+ val textHolder = holder as TextHolder
+ textHolder.bind(items[position] as String)
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (items[position] is MapItem) {
+ TYPE_MAP
+ } else {
+ TYPE_TEXT
+ }
+ }
+
+ fun onSaveInstanceState(savedInstanceState: Bundle?){
+ savedInstanceState?.let {
+ mapHolder?.mapView?.onSaveInstanceState(it)
+ }
+ }
+
+ fun onLowMemory() {
+ mapHolder?.mapView?.onLowMemory()
+ }
+
+ fun onDestroy() {
+ mapHolder?.mapView?.let {
+ it.onPause()
+ it.onStop()
+ it.onDestroy()
+ }
+ }
+
+ class MapItem
+ class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) {
+ init {
+ mapView.onCreate(bundle)
+ mapView.setOnTouchListener { view, motionEvent ->
+ // Disallow the touch request for recyclerView scroll
+ view.parent.requestDisallowInterceptTouchEvent(true)
+ mapView.onTouchEvent(motionEvent)
+ true
+ }
+ }
+ }
+ class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
+ fun bind(item: String) {
+ textView.text = item
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java
index 9f1e7b9956..f98cffecc9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterActivity.java
@@ -27,7 +27,6 @@ public class MapSnapshotterActivity extends AppCompatActivity {
private GridLayout grid;
private List<MapSnapshotter> snapshotters = new ArrayList<>();
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -69,7 +68,7 @@ public class MapSnapshotterActivity extends AppCompatActivity {
// Optionally the style
.withStyle((column + row) % 2 == 0 ? Style.MAPBOX_STREETS : Style.DARK)
- .withLocalIdeographFontFamily("sans-serif");
+ .withLocalIdeographFontFamily("sans-serif");
// Optionally the visible region
if (row % 2 == 0) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
index 51442894e1..3da56d1c82 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
@@ -24,7 +24,7 @@
mapbox:mapbox_cameraTargetLat="38.913187"
mapbox:mapbox_cameraTargetLng="-77.032546"
mapbox:mapbox_cameraZoom="12"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v10" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v11" />
<!-- SF -->
<fragment
@@ -36,7 +36,7 @@
mapbox:mapbox_cameraTargetLat="37.775732"
mapbox:mapbox_cameraTargetLng="-122.413985"
mapbox:mapbox_cameraZoom="13"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/outdoors-v10" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/outdoors-v11" />
</LinearLayout>
<LinearLayout
@@ -56,7 +56,7 @@
mapbox:mapbox_cameraTargetLat="12.97913"
mapbox:mapbox_cameraTargetLng="77.59188"
mapbox:mapbox_cameraZoom="14"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/light-v9" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/light-v10" />
<!-- Ayacucho -->
<fragment
@@ -68,6 +68,6 @@
mapbox:mapbox_cameraTargetLat="-13.155980"
mapbox:mapbox_cameraTargetLng="-74.217134"
mapbox:mapbox_cameraZoom="15"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/dark-v9" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/dark-v10" />
</LinearLayout>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml
new file mode 100644
index 0000000000..7d57f112b7
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_recyclerview.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
index b8ea3d847e..9e5312f067 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
@@ -12,6 +12,6 @@
mapbox:mapbox_cameraTargetLat="47.6077"
mapbox:mapbox_cameraTargetLng="-122.3421"
mapbox:mapbox_cameraZoom="11"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v10" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v11" />
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml
new file mode 100644
index 0000000000..c4c17a25ff
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.mapbox.mapboxsdk.maps.MapView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="256dp"
+ app:mapbox_cameraTargetLat="45.38301927899065"
+ app:mapbox_cameraTargetLng="8.63525390625"
+ app:mapbox_renderTextureMode="true"
+ app:mapbox_cameraZoom="7"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index 67447bce74..abd46d4c8c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -76,4 +76,5 @@
<string name="description_location_modes">Showcases location render and tracking modes</string>
<string name="description_location_fragment">Uses LocationComponent in a Fragment</string>
<string name="description_location_manual">Force location updates and don\'t rely on the engine</string>
+ <string name="description_recyclerview">Show a MapView as a recyclerView item</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
index a0525171a5..faa994e978 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
@@ -48,6 +48,8 @@
<item name="mapbox_accuracyColor">#FF82C6</item>
<item name="mapbox_elevation">0dp</item>
+ <item name="mapbox_compassAnimationEnabled">false</item>
+ <item name="mapbox_accuracyAnimationEnabled">false</item>
</style>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index efd7476c4d..dd7900478b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -76,4 +76,5 @@
<string name="activity_location_modes">Location Modes Activity</string>
<string name="activity_location_fragment">Location Fragment</string>
<string name="activity_location_manual">Manual Location updates</string>
+ <string name="activity_recyclerview">RecyclerView</string>
</resources> \ No newline at end of file
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index 9f9f1f7547..bdff055b23 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -9,7 +9,7 @@ ext {
versions = [
mapboxServices : '3.4.1',
- mapboxTelemetry : '3.5.6',
+ mapboxTelemetry : '3.5.7',
mapboxGestures : '0.3.0',
supportLib : '27.1.1',
constraintLayout: '1.1.2',
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index 84af82d181..1ebfd73849 100644
--- a/platform/android/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Mon May 14 12:12:39 CEST 2018
+#Wed Dec 19 09:48:04 CET 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index f12c48f938..2145a23354 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -186,6 +186,15 @@ void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) {
javaPeer.get(*_env).Call(*_env, onDidFinishRenderingMap, (jboolean) (mode != MapObserver::RenderMode::Partial));
}
+void NativeMapView::onDidBecomeIdle() {
+ assert(vm != nullptr);
+
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto& javaClass = jni::Class<NativeMapView>::Singleton(*_env);
+ static auto onDidBecomeIdle = javaClass.GetMethod<void ()>(*_env, "onDidBecomeIdle");
+ javaPeer.get(*_env).Call(*_env, onDidBecomeIdle);
+}
+
void NativeMapView::onDidFinishLoadingStyle() {
assert(vm != nullptr);
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 08f1efa46d..91d915d58f 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -67,6 +67,7 @@ public:
void onDidFinishRenderingFrame(MapObserver::RenderMode) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(MapObserver::RenderMode) override;
+ void onDidBecomeIdle() override;
void onDidFinishLoadingStyle() override;
void onSourceChanged(mbgl::style::Source&) override;
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 77dd2e4ef4..535f44a7fb 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -230,6 +230,19 @@ NS_ASSUME_NONNULL_BEGIN
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
/**
+ Tells the delegate that the map view is entering an idle state, and no more
+ drawing will be necessary until new data is loaded or there is some interaction
+ with the map.
+
+ - No camera transitions are in progress
+ - All currently requested tiles have loaded
+ - All fade/transition animations have completed
+
+ @param mapView The map view that has just entered the idle state.
+ */
+- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView;
+
+/**
Tells the delegate that the map has just finished loading a style.
This method is called during the initialization of the map view and after any
diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
index 4904cb185b..2bf3dc06bd 100644
--- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
+++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
@@ -52,6 +52,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, didUpdate userLocation: MGLUserLocation?) {}
func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapViewDidBecomeIdle(_ mapView: MGLMapView) {}
func mapView(_ mapView: MGLMapView, didFailToLocateUserWithError error: Error) {}
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 9f9bb855d2..d142271576 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -928,6 +928,16 @@ public:
}
}
+- (void)mapViewDidBecomeIdle {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewDidBecomeIdle)]) {
+ [self.delegate mapViewDidBecomeIdle:self];
+ }
+}
+
- (void)mapViewDidFinishLoadingStyle {
if (!_mbglMap) {
return;
@@ -3012,6 +3022,10 @@ public:
bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
[nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
}
+
+ void onDidBecomeIdle() override {
+ [nativeView mapViewDidBecomeIdle];
+ }
void onDidFinishLoadingStyle() override {
[nativeView mapViewDidFinishLoadingStyle];
diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h
index 2a8b28c1b4..c7d6786666 100644
--- a/platform/macos/src/MGLMapViewDelegate.h
+++ b/platform/macos/src/MGLMapViewDelegate.h
@@ -152,6 +152,19 @@ NS_ASSUME_NONNULL_BEGIN
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
/**
+ Tells the delegate that the map view is entering an idle state, and no more
+ drawing will be necessary until new data is loaded or there is some interaction
+ with the map.
+
+ - No camera transitions are in progress
+ - All currently requested tiles have loaded
+ - All fade/transition animations have completed
+
+ @param mapView The map view that has just entered the idle state.
+ */
+- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView;
+
+/**
Tells the delegate that the map has just finished loading a style.
This method is called during the initialization of the map view and after any
diff --git a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
index 00635d97eb..83c7160fde 100644
--- a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
+++ b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
@@ -24,6 +24,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapViewDidFinishRenderingFrame(_ mapView: MGLMapView, fullyRendered: Bool) {}
func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapViewDidBecomeIdle(_ mapView: MGLMapView) {}
func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}
diff --git a/scripts/changelog_staging/idle-event.json b/scripts/changelog_staging/idle-event.json
new file mode 100644
index 0000000000..96db06eb99
--- /dev/null
+++ b/scripts/changelog_staging/idle-event.json
@@ -0,0 +1,6 @@
+{
+ "core": "Add onDidEnterIdle to MapObserver, which fires whenever render completes and no repaint is scheduled.",
+ "darwin": "Add mapViewDidEnterIdle to MGLMapViewDelegate, which fires whenever render completes and no repaint is scheduled.",
+ "android": "Add onDidEnterIdle listener to MapView, which fires whenever render completes and no repaint is scheduled.",
+ "issue": 13469
+}
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 1f64cf3acc..dc16fe46ce 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -208,6 +208,8 @@ void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepai
if (needsRepaint || transform.inTransition()) {
onUpdate();
+ } else if (rendererFullyLoaded) {
+ observer.onDidBecomeIdle();
}
} else if (stillImageRequest && rendererFullyLoaded) {
auto request = std::move(stillImageRequest);