summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com')
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt1182
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt404
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt113
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapFragmentReadyIdlingResource.kt39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapReadyIdlingResource.java63
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java50
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java14
11 files changed, 1961 insertions, 6 deletions
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
new file mode 100644
index 0000000000..aa3e2eea6f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
@@ -0,0 +1,1182 @@
+package com.mapbox.mapboxsdk.location
+
+import android.Manifest
+import android.R
+import android.content.Context
+import android.graphics.Color
+import android.graphics.RectF
+import android.location.Location
+import android.support.test.espresso.Espresso.onView
+import android.support.test.espresso.IdlingRegistry
+import android.support.test.espresso.UiController
+import android.support.test.espresso.assertion.ViewAssertions.matches
+import android.support.test.espresso.matcher.ViewMatchers.*
+import android.support.test.rule.GrantPermissionRule
+import android.support.test.runner.AndroidJUnit4
+import android.support.v4.content.ContextCompat
+import com.mapbox.geojson.Point
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
+import com.mapbox.mapboxsdk.constants.Style
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.location.LocationComponentConstants.*
+import com.mapbox.mapboxsdk.location.modes.CameraMode
+import com.mapbox.mapboxsdk.location.modes.RenderMode
+import com.mapbox.mapboxsdk.location.utils.*
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAPBOX_HEAVY_STYLE
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAP_CONNECTION_DELAY
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAP_RENDER_DELAY
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.pushSourceUpdates
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest
+import com.mapbox.mapboxsdk.testapp.activity.SingleActivity
+import com.mapbox.mapboxsdk.utils.ColorUtils
+import org.hamcrest.CoreMatchers.*
+import org.junit.*
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LocationComponentTest : BaseActivityTest() {
+
+ @Rule
+ @JvmField
+ val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_FINE_LOCATION)
+
+ override fun getActivityClass(): Class<*> {
+ return SingleActivity::class.java
+ }
+
+ private lateinit var styleChangeIdlingResource: StyleChangeIdlingResource
+ private val location: Location by lazy {
+ val initLocation = Location("")
+ initLocation.latitude = 15.0
+ initLocation.longitude = 17.0
+ initLocation.bearing = 10f
+ initLocation.accuracy = 150f
+ initLocation
+ }
+
+ @Before
+ override fun beforeTest() {
+ super.beforeTest()
+ styleChangeIdlingResource = StyleChangeIdlingResource()
+ IdlingRegistry.getInstance().register(styleChangeIdlingResource)
+ }
+
+ @Test
+ fun locationComponent_initializesLocationEngineCorrectlyWhenOnesNotProvided() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context)
+ component.isLocationComponentEnabled = true
+
+ val locationEngine = component.locationEngine
+ assertThat(locationEngine, notNullValue())
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ assertThat(locationEngine?.isConnected, `is`(true))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponent_initializesLocationEngineCorrectlyWhenOnesNotProvidedButHasOptions() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(
+ context,
+ LocationComponentOptions.builder(context)
+ .staleStateTimeout(200)
+ .enableStaleState(false)
+ .accuracyAlpha(.5f)
+ .accuracyColor(Color.BLUE)
+ .build())
+ component.isLocationComponentEnabled = true
+
+ val locationEngine = component.locationEngine
+ val componentOptions = component.locationComponentOptions
+
+ assertThat(locationEngine, notNullValue())
+ assertThat(componentOptions, notNullValue())
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ assertThat(locationEngine?.isConnected, `is`(true))
+ assertThat(componentOptions?.accuracyAlpha(), `is`(.5f))
+ assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponent_doesntInitializeEngineWhenNullProvided() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(
+ context,
+ null,
+ LocationComponentOptions.builder(context)
+ .staleStateTimeout(200)
+ .enableStaleState(false)
+ .accuracyAlpha(.5f)
+ .accuracyColor(Color.BLUE)
+ .build())
+ component.isLocationComponentEnabled = true
+
+ val locationEngine = component.locationEngine
+ val componentOptions = component.locationComponentOptions
+
+ assertThat(locationEngine, nullValue())
+ assertThat(componentOptions, notNullValue())
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ assertThat(componentOptions?.accuracyAlpha(), `is`(.5f))
+ assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun settingMapStyleImmediatelyBeforeLoadingComponent_doesStillLoadLayersProperly() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ mapboxMap.setStyle(Style.LIGHT)
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL)))
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponent_doesntShowUntilFirstLocationFix() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+
+ // Source should be present but empty
+ val mapView = (rule.activity as SingleActivity).mapView
+ assertThat(mapboxMap.queryRenderedFeatures(
+ RectF(0f, 0f, mapView.width.toFloat(), mapView.height.toFloat()), FOREGROUND_LAYER)
+ .isEmpty(), `is`(true))
+
+ // Force the first location update
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ // Check if the puck is visible
+ assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ //
+ // Location Layer Options
+ //
+
+ @Test
+ fun locationComponentOptions_disablingStaleStateDoesWorkCorrectly() {
+ validateTestSetup()
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .staleStateTimeout(200)
+ .enableStaleState(false)
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ uiController.loopMainThreadForAtLeast(500)
+
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE).also {
+ it.forEach {
+ assertThat(it.getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false))
+ }
+ }
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponentOptions_loadsForegroundBitmapFromNameOption() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .foregroundName("custom-foreground-bitmap")
+ .backgroundName("custom-background-bitmap")
+ .foregroundStaleName("custom-foreground-stale-bitmap")
+ .backgroundStaleName("custom-background-stale-bitmap")
+ .bearingName("custom-bearing-bitmap")
+ .build())
+ component.isLocationComponentEnabled = true
+
+ val foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.ic_media_play)
+ foregroundDrawable?.let {
+ mapboxMap.addImageFromDrawable("custom-foreground-bitmap", it)
+ mapboxMap.addImageFromDrawable("custom-background-bitmap", it)
+ mapboxMap.addImageFromDrawable("custom-foreground-stale-bitmap", it)
+ mapboxMap.addImageFromDrawable("custom-background-stale-bitmap", it)
+ mapboxMap.addImageFromDrawable("custom-bearing-bitmap", it)
+ }
+
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false))
+
+ val feature = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
+ assertThat(feature.getStringProperty(PROPERTY_FOREGROUND_ICON), `is`(equalTo("custom-foreground-bitmap")))
+ assertThat(feature.getStringProperty(PROPERTY_BACKGROUND_ICON), `is`(equalTo("custom-background-bitmap")))
+ assertThat(feature.getStringProperty(PROPERTY_FOREGROUND_STALE_ICON), `is`(equalTo("custom-foreground-stale-bitmap")))
+ assertThat(feature.getStringProperty(PROPERTY_BACKGROUND_STALE_ICON), `is`(equalTo("custom-background-stale-bitmap")))
+ assertThat(feature.getStringProperty(PROPERTY_BEARING_ICON), `is`(equalTo("custom-bearing-bitmap")))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponentOptions_loadsGpsNameWithGpsRenderMode() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .foregroundName("custom-foreground-bitmap")
+ .gpsName("custom-gps-bitmap")
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.renderMode = RenderMode.GPS
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ val foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.ic_media_play)
+ foregroundDrawable?.let {
+ mapboxMap.addImageFromDrawable("custom-foreground-bitmap", it)
+ mapboxMap.addImageFromDrawable("custom-gps-bitmap", it)
+ }
+
+ val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
+ assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponentOptions_customIconNameRevertsToDefault() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .foregroundName("custom-foreground-bitmap")
+ .gpsName("custom-gps-bitmap")
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.renderMode = RenderMode.GPS
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
+ assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
+
+ component.applyStyle(LocationComponentOptions.builder(context).build())
+
+ val renderCheck = {
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) == FOREGROUND_ICON
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+ assertThat(renderCheck.invoke(), `is`(true))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponentOptions_customGpsIconNameChangeBackWithMode() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .gpsName("custom-gps-bitmap")
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.renderMode = RenderMode.GPS
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
+ assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
+
+ component.renderMode = RenderMode.NORMAL
+
+ val renderCheck = {
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) == FOREGROUND_ICON
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+ assertThat(renderCheck.invoke(), `is`(true))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun stillStaleAfterResuming() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .staleStateTimeout(200)
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ uiController.loopMainThreadForAtLeast(250) // engaging stale state
+
+ val renderCheck = {
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE)
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+ assertThat(renderCheck.invoke(), `is`(true))
+
+ component.onStop()
+ component.onStart()
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun stillNotStaleAfterResuming() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false))
+
+ component.onStop()
+ component.onStart()
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun locationComponentOptions_accuracyRingWithColor() {
+ val color = Color.parseColor("#4A90E2")
+ val rgbaColor = ColorUtils.colorToRgbaString(color)
+
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context,
+ null,
+ LocationComponentOptions.builder(context)
+ .accuracyColor(color)
+ .build())
+ component.isLocationComponentEnabled = true
+
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ // Check that the source property changes correctly
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE).also {
+ it.forEach {
+ assertThat(it.getStringProperty(PROPERTY_ACCURACY_COLOR), `is`(equalTo(rgbaColor)))
+ }
+ }
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun forceLocationUpdate_doesMoveLocationLayerIconToCorrectPosition() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
+
+ assertThat(component.locationEngine, nullValue())
+ assertEquals(point.latitude(), location.latitude, 0.1)
+ assertEquals(point.longitude(), location.longitude, 0.1)
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun disablingComponentHidesPuck() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val point: Point = mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER)[0].geometry() as Point
+ assertEquals(point.latitude(), location.latitude, 0.1)
+ assertEquals(point.longitude(), location.longitude, 0.1)
+
+ component.isLocationComponentEnabled = false
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, true)
+ assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun disablingComponentAndChangingStyleAllowsToEnableAgain() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ component.isLocationComponentEnabled = false
+ mapboxMap.setStyle(Style.LIGHT)
+
+ component.isLocationComponentEnabled = true
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_isDisabledOnStart() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ assertThat(component.isLocationComponentEnabled, `is`(false))
+ component.onStop()
+ component.onStart()
+ assertThat(component.isLocationComponentEnabled, `is`(false))
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ assertThat(component.isLocationComponentEnabled, `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_keepsEnabledWhenStoppedAndStarted() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ assertThat(component.isLocationComponentEnabled, `is`(true))
+ component.onStop()
+ component.onStart()
+ assertThat(component.isLocationComponentEnabled, `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_keepsDisabledWhenStoppedAndStarted() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.isLocationComponentEnabled = false
+ assertThat(component.isLocationComponentEnabled, `is`(false))
+ component.onStop()
+ component.onStart()
+ assertThat(component.isLocationComponentEnabled, `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_ableToChangeStyleAfterResuming() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+
+ component.onStop()
+ component.onStart()
+
+ mapboxMap.setStyle(Style.DARK)
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_interruptedDuringStyleChange() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ mapboxMap.setStyle(Style.DARK)
+ component.onStop()
+ component.onStart()
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_forceLocationUpdateAfterStopped() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.onStop()
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE).isEmpty(), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_acceptAndReuseLocationUpdatesBeforeLayerStarted() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.onStop()
+ component.forceLocationUpdate(location)
+ component.onStart()
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
+ assertEquals(point.latitude(), location.latitude, 0.1)
+ assertEquals(point.longitude(), location.longitude, 0.1)
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun lifecycle_lifecycleChangeRightAfterStyleReload() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.setStyle(Style.LIGHT)
+ component.onStop()
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ component.onStart()
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
+ assertEquals(point.latitude(), location.latitude, 0.1)
+ assertEquals(point.longitude(), location.longitude, 0.1)
+
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun mapChange_settingComponentStyle() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE)
+ val options = LocationComponentOptions.builder(context)
+ .accuracyColor(Color.RED)
+ .build()
+
+ pushSourceUpdates(styleChangeIdlingResource) {
+ component.applyStyle(options)
+ }
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ }
+ }
+ executeComponentTest(componentAction)
+
+ // Waiting for style to finish loading while pushing updates
+ onView(withId(R.id.content)).check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun mapChange_forcingLocation() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE)
+
+ pushSourceUpdates(styleChangeIdlingResource) {
+ component.forceLocationUpdate(location)
+ }
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ }
+ }
+ executeComponentTest(componentAction)
+
+ // Waiting for style to finish loading while pushing updates
+ onView(withId(R.id.content)).check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun mapChange_settingMapStyleBeforeComponentCreation() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE)
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+
+ val options = LocationComponentOptions.builder(context)
+ .accuracyColor(Color.RED)
+ .build()
+
+ pushSourceUpdates(styleChangeIdlingResource) {
+ component.forceLocationUpdate(location)
+ component.applyStyle(options)
+ }
+ }
+ }
+ executeComponentTest(componentAction)
+
+ // Waiting for style to finish loading while pushing updates
+ onView(withId(R.id.content)).check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun animators_layerBearingCorrect() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.GPS
+ location.bearing = 77f
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+ assertEquals(77.0, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING) as Double, 0.1)
+
+ location.bearing = 92f
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY) // Waiting for the animation to finish
+ assertEquals(92.0, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING) as Double, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_cameraLatLngBearingCorrect() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING_GPS
+ location.bearing = 77f
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+ assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(location.latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(location.longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+
+ location.bearing = 92f
+ location.latitude = 30.0
+ location.longitude = 35.0
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY) // Waiting for the animation to finish
+ assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(location.latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(location.longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_cameraBearingCorrect() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.NONE_GPS
+ val latitude = mapboxMap.cameraPosition.target.latitude
+ val longitude = mapboxMap.cameraPosition.target.longitude
+
+ location.bearing = 77f
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+ assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+
+ location.bearing = 92f
+ location.latitude = 30.0
+ location.longitude = 35.0
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+ assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_cameraNoneCorrect() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.NONE
+ val latitude = mapboxMap.cameraPosition.target.latitude
+ val longitude = mapboxMap.cameraPosition.target.longitude
+ val bearing = mapboxMap.cameraPosition.bearing
+
+ location.bearing = 77f
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+ assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+
+ location.bearing = 92f
+ location.latitude = 30.0
+ location.longitude = 35.0
+ component.forceLocationUpdate(location)
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY) // Waiting for the animation to finish
+ assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_focalPointAdjustment() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.cameraMode = CameraMode.NONE
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(mapboxMap.uiSettings.focalPoint, nullValue())
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_dontZoomWhileNotTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.NONE
+ val zoom = mapboxMap.cameraPosition.zoom
+ component.zoomWhileTracking(10.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
+
+ assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_zoomWhileTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.zoomWhileTracking(10.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
+
+ assertEquals(10.0, mapboxMap.cameraPosition.zoom, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ @Ignore
+ fun animators_zoomWhileTrackingCanceledOnModeChange() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.zoomWhileTracking(15.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
+ component.cameraMode = CameraMode.NONE
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
+
+ assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_dontZoomWhileStopped() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+
+ component.cameraMode = CameraMode.TRACKING
+ val zoom = mapboxMap.cameraPosition.zoom
+
+ component.onStop()
+ component.zoomWhileTracking(10.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
+
+ assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ @Ignore
+ fun animators_cancelZoomWhileTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.zoomWhileTracking(15.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
+ component.cancelZoomWhileTrackingAnimation()
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
+
+ assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_dontTiltWhileNotTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.NONE
+ val tilt = mapboxMap.cameraPosition.tilt
+ component.tiltWhileTracking(30.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
+
+ assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_tiltWhileTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.tiltWhileTracking(30.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
+
+ assertEquals(30.0, mapboxMap.cameraPosition.tilt, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ @Ignore
+ fun animators_tiltWhileTrackingCanceledOnModeChange() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.tiltWhileTracking(30.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
+ component.cameraMode = CameraMode.NONE
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
+
+ assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun animators_dontTiltWhileStopped() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ val tilt = mapboxMap.cameraPosition.tilt
+
+ component.onStop()
+ component.tiltWhileTracking(30.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
+
+ assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ @Ignore
+ fun animators_cancelTiltWhileTracking() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING
+ component.tiltWhileTracking(30.0)
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
+ component.cancelTiltWhileTrackingAnimation()
+ uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
+
+ assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun cameraPositionAdjustedToTrackingModeWhenComponentEnabled() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.cameraMode = CameraMode.TRACKING_GPS
+ component.forceLocationUpdate(location)
+ component.isLocationComponentEnabled = false
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0)))
+ mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0))
+ component.isLocationComponentEnabled = true
+ uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS + MAP_RENDER_DELAY)
+
+ assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1)
+ assertEquals(location.latitude, mapboxMap.cameraPosition.target.latitude, 0.1)
+ assertEquals(location.longitude, mapboxMap.cameraPosition.target.longitude, 0.1)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun compassEngine_onComponentInitializedDefaultIsProvided() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ assertTrue(component.compassEngine is LocationComponentCompassEngine)
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun compassEngine_changesWhenNewProvided() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ val engine: CompassEngine = object : CompassEngine {
+ override fun addCompassListener(compassListener: CompassListener) {
+ }
+
+ override fun removeCompassListener(compassListener: CompassListener) {
+ }
+
+ override fun getLastHeading(): Float {
+ return 0f
+ }
+
+ override fun getLastAccuracySensorStatus(): Int {
+ return 0
+ }
+
+ override fun onStart() {
+ }
+
+ override fun onStop() {
+ }
+ }
+
+ component.compassEngine = engine
+ assertThat(component.compassEngine, notNullValue())
+ assertThat(component.compassEngine, `is`(equalTo(engine)))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun defaultLocationEngine_deactivatedWhenDestroyed() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context)
+ component.isLocationComponentEnabled = true
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ assertThat(component.locationEngine?.isConnected, `is`(true))
+
+ component.onStop()
+ component.onDestroy()
+ assertThat(component.locationEngine?.isConnected, `is`(false))
+ }
+ }
+
+ executeComponentTest(componentAction)
+ }
+
+ @After
+ override fun afterTest() {
+ super.afterTest()
+ IdlingRegistry.getInstance().unregister(styleChangeIdlingResource)
+ }
+
+ private fun executeComponentTest(listener: LocationComponentAction.OnPerformLocationComponentAction) {
+ onView(withId(R.id.content)).perform(LocationComponentAction(mapboxMap, listener))
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt
new file mode 100644
index 0000000000..41a349b993
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt
@@ -0,0 +1,404 @@
+package com.mapbox.mapboxsdk.location
+
+import android.Manifest
+import android.R
+import android.content.Context
+import android.location.Location
+import android.support.test.espresso.Espresso.onView
+import android.support.test.espresso.IdlingRegistry
+import android.support.test.espresso.UiController
+import android.support.test.espresso.assertion.ViewAssertions.matches
+import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
+import android.support.test.espresso.matcher.ViewMatchers.withId
+import android.support.test.rule.GrantPermissionRule
+import android.support.test.rule.GrantPermissionRule.grant
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
+import com.mapbox.mapboxsdk.constants.Style
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.location.LocationComponentConstants.*
+import com.mapbox.mapboxsdk.location.modes.RenderMode
+import com.mapbox.mapboxsdk.location.utils.*
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAPBOX_HEAVY_STYLE
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAP_CONNECTION_DELAY
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.MAP_RENDER_DELAY
+import com.mapbox.mapboxsdk.location.utils.MapboxTestingUtils.Companion.pushSourceUpdates
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest
+import com.mapbox.mapboxsdk.testapp.activity.SingleActivity
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.CoreMatchers.notNullValue
+import org.hamcrest.Matchers.equalTo
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class LocationLayerControllerTest : BaseActivityTest() {
+
+ @Rule
+ @JvmField
+ val permissionRule: GrantPermissionRule = grant(Manifest.permission.ACCESS_FINE_LOCATION)
+
+ override fun getActivityClass(): Class<*> {
+ return SingleActivity::class.java
+ }
+
+ private lateinit var styleChangeIdlingResource: StyleChangeIdlingResource
+ private val location: Location by lazy {
+ val initLocation = Location("")
+ initLocation.latitude = 15.0
+ initLocation.longitude = 17.0
+ initLocation.bearing = 10f
+ initLocation.accuracy = 150f
+ initLocation
+ }
+
+ @Before
+ override fun beforeTest() {
+ super.beforeTest()
+ styleChangeIdlingResource = StyleChangeIdlingResource()
+ IdlingRegistry.getInstance().register(styleChangeIdlingResource)
+ }
+
+ //
+ // Location Source
+ //
+
+ @Test
+ fun renderModeNormal_sourceDoesGetAdded() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.NORMAL
+ uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY)
+ assertThat(mapboxMap.getSource(LOCATION_SOURCE), notNullValue())
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ //
+ // Location Layers
+ //
+
+ @Test
+ fun renderModeNormal_trackingNormalLayersDoGetAdded() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.NORMAL
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun renderModeCompass_bearingLayersDoGetAdded() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.COMPASS
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun renderModeGps_navigationLayersDoGetAdded() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.GPS
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun dontShowPuckWhenRenderModeSetAndComponentDisabled() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ component.isLocationComponentEnabled = false
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true)
+ component.renderMode = RenderMode.GPS
+
+ // waiting for layer to appear or timing out
+ val renderCheck = {
+ mapboxMap.isLayerVisible(FOREGROUND_LAYER)
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun whenLocationComponentDisabled_doesSetAllLayersToVisibilityNone() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.NORMAL
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ component.isLocationComponentEnabled = false
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true)
+
+ // Check that all layers visibilities are set to none
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun onMapChange_locationComponentLayersDoGetRedrawn() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.renderMode = RenderMode.NORMAL
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ mapboxMap.setStyleUrl(Style.LIGHT)
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL)))
+
+ // Check that the Source has been re-added to the new map style
+ val source: GeoJsonSource? = mapboxMap.getSourceAs(LOCATION_SOURCE)
+ assertThat(source, notNullValue())
+
+ // Check that all layers visibilities are set to visible
+ assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(SHADOW_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
+ assertThat(mapboxMap.isLayerVisible(BEARING_LAYER), `is`(false))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun whenStyleChanged_continuesUsingStaleIcons() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build())
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ uiController.loopMainThreadForAtLeast(150)
+
+ val renderCheck = {
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE)
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+
+ assertThat(renderCheck.invoke(), `is`(true))
+
+ mapboxMap.setStyleUrl(Style.LIGHT)
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun whenStyleChanged_staleStateChanges() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(1).build())
+ styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE)
+ pushSourceUpdates(styleChangeIdlingResource) {
+ component.forceLocationUpdate(location)
+ }
+ }
+ }
+ executeComponentTest(componentAction)
+
+ // Waiting for style to finish loading while pushing updates
+ onView(withId(R.id.content)).check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun whenStyleChanged_layerVisibilityUpdates() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE)
+ var show = true
+ component.activateLocationComponent(context, false)
+ pushSourceUpdates(styleChangeIdlingResource) {
+ component.isLocationComponentEnabled = show
+ show = !show
+ }
+
+ uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY)
+ }
+ }
+ executeComponentTest(componentAction)
+
+ // Waiting for style to finish loading while pushing updates
+ onView(withId(R.id.content)).check(matches(isDisplayed()))
+ }
+
+ @Test
+ fun accuracy_visibleWithNewLocation() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0))
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+ uiController.loopMainThreadForAtLeast(ACCURACY_RADIUS_ANIMATION_DURATION)
+
+ assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/,
+ mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
+ .getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f)
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun accuracy_visibleWhenCameraEased() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val target = LatLng(location)
+ val zoom = 16.0
+ mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(target, zoom), 300)
+ uiController.loopMainThreadForAtLeast(300)
+
+ val cameraCheck = {
+ Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1
+ && Math.abs(target.latitude - mapboxMap.cameraPosition.target.latitude) < 0.1
+ && Math.abs(target.longitude - mapboxMap.cameraPosition.target.longitude) < 0.1
+ }
+ waitForRenderResult(uiController, cameraCheck, true)
+
+ val expectedRadius = Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/
+ val renderCheck = {
+ Math.abs(expectedRadius - mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat()) < 0.1
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+
+ assertThat(renderCheck.invoke(), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @Test
+ fun accuracy_visibleWhenCameraMoved() {
+ val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
+ override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
+ uiController: UiController, context: Context) {
+ component.activateLocationComponent(context, false)
+ component.isLocationComponentEnabled = true
+ component.forceLocationUpdate(location)
+ mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER)
+
+ val target = LatLng(location)
+ val zoom = 16.0
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(target, zoom))
+
+ val cameraCheck = {
+ Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1
+ && Math.abs(target.latitude - mapboxMap.cameraPosition.target.latitude) < 0.1
+ && Math.abs(target.longitude - mapboxMap.cameraPosition.target.longitude) < 0.1
+ }
+ waitForRenderResult(uiController, cameraCheck, true)
+
+ val expectedRadius = Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/
+ val renderCheck = {
+ Math.abs(expectedRadius - mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat()) < 0.1
+ }
+ waitForRenderResult(uiController, renderCheck, true)
+
+ assertThat(renderCheck.invoke(), `is`(true))
+ }
+ }
+ executeComponentTest(componentAction)
+ }
+
+ @After
+ override fun afterTest() {
+ super.afterTest()
+ IdlingRegistry.getInstance().unregister(styleChangeIdlingResource)
+ }
+
+ private fun executeComponentTest(listener: LocationComponentAction.OnPerformLocationComponentAction) {
+ onView(withId(R.id.content)).perform(LocationComponentAction(mapboxMap, listener))
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt
new file mode 100644
index 0000000000..75fae82cf2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.location.utils
+
+import android.content.Context
+import android.support.test.espresso.UiController
+import android.support.test.espresso.ViewAction
+import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
+import android.view.View
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.location.LocationComponent
+import org.hamcrest.Matcher
+
+class LocationComponentAction(private val mapboxMap: MapboxMap,
+ private val onPerformLocationComponentAction: OnPerformLocationComponentAction) : ViewAction {
+
+ override fun getConstraints(): Matcher<View> {
+ return isDisplayed()
+ }
+
+ override fun getDescription(): String {
+ return javaClass.simpleName
+ }
+
+ override fun perform(uiController: UiController, view: View) {
+ onPerformLocationComponentAction.onLocationComponentAction(
+ mapboxMap.locationComponent,
+ mapboxMap,
+ uiController,
+ view.context)
+ }
+
+ interface OnPerformLocationComponentAction {
+ fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, uiController: UiController, context: Context)
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt
new file mode 100644
index 0000000000..7d362a6f76
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt
@@ -0,0 +1,113 @@
+package com.mapbox.mapboxsdk.location.utils
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.location.Location
+import android.os.Handler
+import android.os.Looper
+import android.support.test.espresso.UiController
+import com.mapbox.geojson.Feature
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.style.layers.Property
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
+
+fun MapboxMap.querySourceFeatures(sourceId: String): List<Feature> {
+ return this.getSourceAs<GeoJsonSource>(sourceId)?.querySourceFeatures(null) ?: emptyList()
+}
+
+fun MapboxMap.queryRenderedFeatures(location: Location, layerId: String): List<Feature> {
+ val latLng = LatLng(location.latitude, location.longitude)
+ val point = this.projection.toScreenLocation(latLng)
+ return this.queryRenderedFeatures(point, layerId)
+}
+
+fun MapboxMap.isLayerVisible(layerId: String): Boolean {
+ return this.getLayer(layerId)?.visibility?.value?.equals(Property.VISIBLE)!!
+}
+
+fun MapboxMap.waitForSource(uiController: UiController, sourceId: String) {
+ var counter = 0
+ val delay = MapboxTestingUtils.MAP_RENDER_DELAY
+ while (this.querySourceFeatures(sourceId).isEmpty() && delay * counter < MapboxTestingUtils.RENDER_TIMEOUT) {
+ uiController.loopMainThreadForAtLeast(delay)
+ counter++
+ }
+}
+
+fun MapboxMap.waitForLayer(uiController: UiController, location: Location, layerId: String, shouldDisappear: Boolean = false) {
+ var counter = 0
+ val delay = MapboxTestingUtils.MAP_RENDER_DELAY
+ while (
+ if (shouldDisappear) this.queryRenderedFeatures(location, layerId).isNotEmpty() else this.queryRenderedFeatures(location, layerId).isEmpty()
+ && delay * counter < MapboxTestingUtils.RENDER_TIMEOUT) {
+ uiController.loopMainThreadForAtLeast(delay)
+ counter++
+ }
+}
+
+inline fun waitForRenderResult(uiController: UiController, checkFunction: () -> Boolean, expectedResult: Boolean) {
+ var counter = 0
+ val delay = MapboxTestingUtils.MAP_RENDER_DELAY
+ while (checkFunction.invoke() != expectedResult && delay * counter < MapboxTestingUtils.RENDER_TIMEOUT) {
+ uiController.loopMainThreadForAtLeast(delay)
+ counter++
+ }
+}
+
+class MapboxTestingUtils {
+ companion object {
+
+ const val MAP_RENDER_DELAY = 250L
+ const val MAP_CONNECTION_DELAY = 1000L
+ const val RENDER_TIMEOUT = 2_500L
+
+ /**
+ * Used to increase style load time for stress testing.
+ */
+ const val MAPBOX_HEAVY_STYLE = "asset://heavy_style.json"
+
+ private const val DATA_PUSH_INTERVAL = 1L
+
+ /**
+ * Pushes data updates every [DATA_PUSH_INTERVAL] milliseconds until the style has been loaded,
+ * checked with [StyleChangeIdlingResource].
+ */
+ fun pushSourceUpdates(styleChangeIdlingResource: StyleChangeIdlingResource, update: () -> Unit) {
+ val mainHandler = Handler(Looper.getMainLooper())
+ val runnable = object : Runnable {
+ override fun run() {
+ update.invoke()
+ if (!styleChangeIdlingResource.isIdleNow) {
+ mainHandler.postDelayed(this, DATA_PUSH_INTERVAL)
+ }
+ }
+ }
+
+ if (!styleChangeIdlingResource.isIdleNow) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ runnable.run()
+ } else {
+ mainHandler.post(runnable)
+ }
+ }
+ }
+ }
+}
+
+fun MapboxMap.addImageFromDrawable(string: String, drawable: Drawable) {
+ val bitmapFromDrawable = getBitmapFromDrawable(drawable)
+ this.addImage(string, bitmapFromDrawable)
+}
+
+private fun getBitmapFromDrawable(drawable: Drawable): Bitmap {
+ if (drawable is BitmapDrawable) return drawable.bitmap
+ val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
+ drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bitmap)
+ drawable.setBounds(0, 0, canvas.width, canvas.height)
+ drawable.draw(canvas)
+ return bitmap
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapFragmentReadyIdlingResource.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapFragmentReadyIdlingResource.kt
new file mode 100644
index 0000000000..4d02a4d2bf
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapFragmentReadyIdlingResource.kt
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.location.utils
+
+import android.os.Handler
+import android.os.Looper
+import android.support.test.espresso.IdlingResource
+
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
+import com.mapbox.mapboxsdk.maps.SupportMapFragment
+
+class OnMapFragmentReadyIdlingResource(fragment: SupportMapFragment?) : IdlingResource, OnMapReadyCallback {
+
+ lateinit var mapboxMap: MapboxMap
+
+ private var resourceCallback: IdlingResource.ResourceCallback? = null
+
+ init {
+ Handler(Looper.getMainLooper()).post {
+ fragment?.getMapAsync(this)
+ }
+ }
+
+ override fun getName(): String {
+ return javaClass.simpleName
+ }
+
+ override fun isIdleNow(): Boolean {
+ return this::mapboxMap.isInitialized
+ }
+
+ override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback) {
+ this.resourceCallback = resourceCallback
+ }
+
+ override fun onMapReady(mapboxMap: MapboxMap) {
+ this.mapboxMap = mapboxMap
+ resourceCallback?.onTransitionToIdle()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapReadyIdlingResource.java
new file mode 100644
index 0000000000..9adb30ee32
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapReadyIdlingResource.java
@@ -0,0 +1,63 @@
+package com.mapbox.mapboxsdk.location.utils;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.espresso.IdlingResource;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+
+import java.lang.reflect.Field;
+
+public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallback {
+
+ private MapboxMap mapboxMap;
+ private MapView mapView;
+ private IdlingResource.ResourceCallback resourceCallback;
+
+ public OnMapReadyIdlingResource(Activity activity) {
+ new Handler(Looper.getMainLooper()).post(() -> {
+ try {
+ Field field = activity.getClass().getDeclaredField("mapView");
+ field.setAccessible(true);
+ mapView = ((MapView) field.get(activity));
+ mapView.getMapAsync(this);
+ } catch (Exception err) {
+ throw new RuntimeException(err);
+ }
+ });
+ }
+
+ @Override
+ public String getName() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean isIdleNow() {
+ return mapboxMap != null;
+ }
+
+ @Override
+ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
+ this.resourceCallback = resourceCallback;
+ }
+
+ public MapView getMapView() {
+ return mapView;
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ if (resourceCallback != null) {
+ resourceCallback.onTransitionToIdle();
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt
new file mode 100644
index 0000000000..0f37498a29
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt
@@ -0,0 +1,46 @@
+package com.mapbox.mapboxsdk.location.utils
+
+import android.support.test.espresso.IdlingResource
+import com.mapbox.mapboxsdk.maps.MapView
+import com.mapbox.mapboxsdk.maps.MapboxMap
+
+/**
+ * Resource, that's idling until the provided style is loaded.
+ * Remember to add any espresso action (like view assertion) after the [waitForStyle] call
+ * for the test to keep running.
+ */
+class StyleChangeIdlingResource : IdlingResource {
+
+ private var callback: IdlingResource.ResourceCallback? = null
+ private var isIdle = true
+
+ override fun getName(): String {
+ return javaClass.simpleName
+ }
+
+ override fun isIdleNow(): Boolean {
+ return isIdle
+ }
+
+ override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
+ this.callback = callback
+ }
+
+ private fun setIdle() {
+ isIdle = true
+ callback?.onTransitionToIdle()
+ }
+
+ fun waitForStyle(mapView: MapView, mapboxMap: MapboxMap, styleUrl: String) {
+ isIdle = false
+ mapView.addOnMapChangedListener(object : MapView.OnMapChangedListener {
+ override fun onMapChanged(change: Int) {
+ if (change == MapView.DID_FINISH_LOADING_STYLE) {
+ mapView.removeOnMapChangedListener(this)
+ setIdle()
+ }
+ }
+ })
+ mapboxMap.setStyleUrl(styleUrl)
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
index 5e8f3ed365..926212afc8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.testapp.action;
+import android.support.annotation.NonNull;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;
@@ -42,7 +43,7 @@ public class MapboxMapAction implements ViewAction {
}
public interface OnInvokeActionListener {
- void onInvokeAction(UiController uiController, MapboxMap mapboxMap);
+ void onInvokeAction(@NonNull UiController uiController, @NonNull MapboxMap mapboxMap);
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
index 5480aa7a1c..3682440aeb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
@@ -4,19 +4,24 @@ import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.support.test.espresso.Espresso;
+import android.support.test.espresso.IdlingRegistry;
import android.support.test.espresso.IdlingResourceTimeoutException;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
+
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
import com.mapbox.mapboxsdk.testapp.action.WaitAction;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+
import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
+import org.junit.rules.TestName;
+
import timber.log.Timber;
import static android.support.test.espresso.Espresso.onView;
@@ -28,15 +33,19 @@ public abstract class BaseActivityTest {
@Rule
public ActivityTestRule<Activity> rule = new ActivityTestRule<>(getActivityClass());
+
+ @Rule
+ public TestName testNameRule = new TestName();
+
protected MapboxMap mapboxMap;
protected OnMapReadyIdlingResource idlingResource;
@Before
public void beforeTest() {
try {
- Timber.e("@Before test: register idle resource");
+ Timber.e(String.format("%s - %s", testNameRule.getMethodName(), "@Before test: register idle resource"));
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ IdlingRegistry.getInstance().register(idlingResource);
checkViewIsDisplayed(R.id.mapView);
mapboxMap = idlingResource.getMapboxMap();
} catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
@@ -91,8 +100,8 @@ public abstract class BaseActivityTest {
@After
public void afterTest() {
- Timber.e("@After test: unregister idle resource");
- Espresso.unregisterIdlingResources(idlingResource);
+ Timber.e(String.format("%s - %s", testNameRule.getMethodName(), "@After test: unregister idle resource"));
+ IdlingRegistry.getInstance().unregister(idlingResource);
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java
new file mode 100644
index 0000000000..f5b4586a86
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/string/UppperLowerCaseTest.java
@@ -0,0 +1,50 @@
+package com.mapbox.mapboxsdk.testapp.string;
+
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+/**
+ * Test verifying if String#toUpperCase and String#toLowerCase produces desired results
+ * <p>
+ * See core test in https://github.com/mapbox/mapbox-gl-native/blob/master/test/util/text_conversions.test.cpp
+ * </p>
+ */
+public class UppperLowerCaseTest extends BaseActivityTest {
+
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+
+ @Test
+ public void testToUpperCase() {
+ assertEquals("STREET", "strEEt".toUpperCase()); // EN
+ assertEquals("ROAD", "rOAd".toUpperCase()); // EN
+
+ assertEquals("STRASSE", "straße".toUpperCase()); // DE
+ assertEquals("MASSE", "maße".toUpperCase()); // DE
+ assertEquals("WEISSKOPFSEEADLER", "weißkopfseeadler".toUpperCase()); // DE
+
+ assertEquals("BÊNÇÃO", "bênção".toUpperCase()); // PT
+ assertEquals("AZƏRBAYCAN", "Azərbaycan".toUpperCase()); // AZ
+ assertEquals("ὈΔΥΣΣΕΎΣ", "Ὀδυσσεύς".toUpperCase()); // GR
+ }
+
+ @Test
+ public void testToLowerCase() {
+ assertEquals("street", "strEEt".toLowerCase()); // EN
+ assertEquals("road", "rOAd".toLowerCase()); // EN
+
+ assertEquals("straße", "Straße".toLowerCase()); // DE
+ assertEquals("strasse", "STRASSE".toLowerCase()); // DE
+ assertEquals("masse", "MASSE".toLowerCase()); // DE
+ assertEquals("weisskopfseeadler", "weiSSkopfseeadler".toLowerCase()); // DE
+
+ assertEquals("bênção", "BÊNÇÃO".toLowerCase()); // PT
+ assertEquals("azərbaycan", "AZƏRBAYCAN".toLowerCase()); //
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
index 8cf452a6cf..98c9c27fc2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
@@ -160,6 +160,20 @@ public class SymbolLayerTest extends BaseActivityTest {
}
@Test
+ public void testSymbolZOrderAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("symbol-z-order");
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(symbolZOrder(SYMBOL_Z_ORDER_VIEWPORT_Y));
+ assertEquals((String) layer.getSymbolZOrder().getValue(), (String) SYMBOL_Z_ORDER_VIEWPORT_Y);
+ });
+ }
+
+ @Test
public void testIconAllowOverlapAsConstant() {
validateTestSetup();
setupLayer();