From 907612e93d8a2b156d4604fda348707ccb347836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 5 Sep 2018 14:30:36 +0200 Subject: [android] updated naming scheme and packages structure for LocationLayerPlugin, now called LocationComponent --- .../mapboxsdk/location/LocationComponentTest.kt | 1104 ++++++++++++++++++++ .../location/LocationLayerControllerTest.kt | 360 +++++++ .../location/utils/LocationComponentAction.kt | 40 + .../mapboxsdk/location/utils/MapboxTestingUtils.kt | 105 ++ .../utils/OnMapFragmentReadyIdlingResource.kt | 39 + .../location/utils/OnMapReadyIdlingResource.java | 63 ++ .../location/utils/StyleChangeIdlingResource.kt | 46 + .../locationlayer/LocationLayerPluginTest.kt | 1104 -------------------- .../plugins/locationlayer/LocationLayerTest.kt | 360 ------- .../plugins/utils/LocationLayerPluginAction.kt | 40 - .../mapboxsdk/plugins/utils/MapboxTestingUtils.kt | 105 -- .../utils/OnMapFragmentReadyIdlingResource.kt | 39 - .../plugins/utils/OnMapReadyIdlingResource.java | 63 -- .../plugins/utils/StyleChangeIdlingResource.kt | 46 - .../src/main/AndroidManifest.xml | 6 +- .../activity/location/LocationFragmentActivity.kt | 171 +++ .../location/LocationLayerFragmentActivity.kt | 171 --- .../location/LocationLayerMapChangeActivity.java | 131 --- .../location/LocationLayerModesActivity.java | 383 ------- .../location/LocationMapChangeActivity.java | 131 +++ .../activity/location/LocationModesActivity.java | 383 +++++++ .../location/ManualLocationUpdatesActivity.java | 22 +- .../src/main/res/menu/menu_location_mode.xml | 4 +- .../src/main/res/values/descriptions.xml | 2 +- .../src/main/res/values/styles.xml | 2 +- 25 files changed, 2460 insertions(+), 2460 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapFragmentReadyIdlingResource.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/OnMapReadyIdlingResource.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/StyleChangeIdlingResource.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPluginTest.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/LocationLayerPluginAction.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/MapboxTestingUtils.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapFragmentReadyIdlingResource.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapReadyIdlingResource.java delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/StyleChangeIdlingResource.kt create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerFragmentActivity.kt delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerMapChangeActivity.java delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerModesActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java (limited to 'platform/android/MapboxGLAndroidSDKTestApp') 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..1d7c0c404b --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -0,0 +1,1104 @@ +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.maps.MapboxMap +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.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) + + 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()) + + 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( + null, + LocationComponentOptions.builder(context) + .staleStateTimeout(200) + .enableStaleState(false) + .accuracyAlpha(.5f) + .accuracyColor(Color.BLUE) + .build()) + + 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.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) + + // 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, + LocationComponentOptions.builder(context) + .staleStateTimeout(200) + .enableStaleState(false) + .build()) + + component.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + uiController.loopMainThreadForAtLeast(200) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + 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, + 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()) + + 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, + LocationComponentOptions.builder(context) + .foregroundName("custom-foreground-bitmap") + .gpsName("custom-gps-bitmap") + .build()) + + 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, + LocationComponentOptions.builder(context) + .foregroundName("custom-foreground-bitmap") + .gpsName("custom-gps-bitmap") + .build()) + + 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()) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + val revertedForegroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) + assertThat(revertedForegroundId, `is`(equalTo(FOREGROUND_ICON))) + } + } + + 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, + LocationComponentOptions.builder(context) + .gpsName("custom-gps-bitmap") + .build()) + + 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 + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + val revertedForegroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) + assertThat(revertedForegroundId, `is`(equalTo(FOREGROUND_ICON))) + } + } + + executeComponentTest(componentAction) + } + + @Test + fun stillStaleAfterResuming() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, + uiController: UiController, context: Context) { + component.activateLocationComponent(context, + LocationComponentOptions.builder(context) + .staleStateTimeout(200) + .build()) + + component.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + uiController.loopMainThreadForAtLeast(250) // engaging stale state + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `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.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) + + component.onStop() + component.onStart() + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + 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, + LocationComponentOptions.builder(context) + .accuracyColor(color) + .build()) + + 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.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.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.deactivateLocationComponent() + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + 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.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + + component.deactivateLocationComponent() + mapboxMap.setStyle(Style.LIGHT) + + component.activateLocationComponent(context, false) + 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.isLocationLayerEnabled, `is`(false)) + component.onStop() + component.onStart() + assertThat(component.isLocationLayerEnabled, `is`(false)) + component.activateLocationComponent(context, false) + assertThat(component.isLocationLayerEnabled, `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) + assertThat(component.isLocationLayerEnabled, `is`(true)) + component.onStop() + component.onStart() + assertThat(component.isLocationLayerEnabled, `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.deactivateLocationComponent() + assertThat(component.isLocationLayerEnabled, `is`(false)) + component.onStop() + component.onStart() + assertThat(component.isLocationLayerEnabled, `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.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) + 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.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.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.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) + 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) + 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) + + 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.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.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.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.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.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.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.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.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.cameraMode = CameraMode.TRACKING + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + 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.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.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.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.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.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.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.cameraMode = CameraMode.TRACKING_GPS + component.forceLocationUpdate(location) + component.deactivateLocationComponent() + mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0))) + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0)) + component.activateLocationComponent(context, false) + 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) + 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) + 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) + } + + @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..c50d1817fd --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -0,0 +1,360 @@ +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.maps.MapboxMap +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.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.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.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.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.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.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + component.deactivateLocationComponent() + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true) + component.renderMode = RenderMode.GPS + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + 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.renderMode = RenderMode.NORMAL + component.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + component.deactivateLocationComponent() + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + // 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.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.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build()) + component.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + uiController.loopMainThreadForAtLeast(150) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + + assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `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.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 + pushSourceUpdates(styleChangeIdlingResource) { + if (show) { + component.activateLocationComponent(context, false) + } else { + component.deactivateLocationComponent() + } + 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) + 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.forceLocationUpdate(location) + mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) + mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0), 300) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300) + + 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_visibleWhenCameraMoved() { + val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction { + override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, + uiController: UiController, context: Context) { + component.activateLocationComponent(context, false) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + component.forceLocationUpdate(location) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) + uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300) + + 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) + } + + @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..ad80a3333e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/LocationComponentAction.kt @@ -0,0 +1,40 @@ +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 { + return isDisplayed() + } + + override fun getDescription(): String { + return javaClass.simpleName + } + + override fun perform(uiController: UiController, view: View) { + val component = mapboxMap.locationComponent + + while (mapboxMap.getSource("mapbox-location-source") == null) { + uiController.loopMainThreadForAtLeast(MapboxTestingUtils.MAP_RENDER_DELAY) + } + + onPerformLocationComponentAction.onLocationComponentAction( + component, + 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..591901385f --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/utils/MapboxTestingUtils.kt @@ -0,0 +1,105 @@ +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 { + return this.getSourceAs(sourceId)?.querySourceFeatures(null) ?: emptyList() +} + +fun MapboxMap.queryRenderedFeatures(location: Location, layerId: String): List { + 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++ + } +} + + +class MapboxTestingUtils { + companion object { + + const val MAP_RENDER_DELAY = 250L + const val MAP_CONNECTION_DELAY = 1000L + const val RENDER_TIMEOUT = 3_000L + + /** + * 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/plugins/locationlayer/LocationLayerPluginTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPluginTest.kt deleted file mode 100644 index e9552f974b..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerPluginTest.kt +++ /dev/null @@ -1,1104 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.locationlayer - -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.maps.MapboxMap -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.* -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.CameraMode -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode -import com.mapbox.mapboxsdk.plugins.utils.* -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAPBOX_HEAVY_STYLE -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAP_CONNECTION_DELAY -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAP_RENDER_DELAY -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.pushSourceUpdates -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 LocationLayerPluginTest : 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("test") - 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 locationLayerPlugin_initializesLocationEngineCorrectlyWhenOnesNotProvided() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context) - - val locationEngine = plugin.locationEngine - assertThat(locationEngine, notNullValue()) - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - assertThat(locationEngine?.isConnected, `is`(true)) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerPlugin_initializesLocationEngineCorrectlyWhenOnesNotProvidedButHasOptions() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin( - context, - LocationLayerOptions.builder(context) - .staleStateTimeout(200) - .enableStaleState(false) - .accuracyAlpha(.5f) - .accuracyColor(Color.BLUE) - .build()) - - val locationEngine = plugin.locationEngine - val pluginOptions = plugin.locationLayerOptions - - assertThat(locationEngine, notNullValue()) - assertThat(pluginOptions, notNullValue()) - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - assertThat(locationEngine?.isConnected, `is`(true)) - assertThat(pluginOptions?.accuracyAlpha(), `is`(.5f)) - assertThat(pluginOptions?.accuracyColor(), `is`(Color.BLUE)) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerPlugin_doesntInitializeEngineWhenNullProvided() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin( - null, - LocationLayerOptions.builder(context) - .staleStateTimeout(200) - .enableStaleState(false) - .accuracyAlpha(.5f) - .accuracyColor(Color.BLUE) - .build()) - - val locationEngine = plugin.locationEngine - val pluginOptions = plugin.locationLayerOptions - - assertThat(locationEngine, nullValue()) - assertThat(pluginOptions, notNullValue()) - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - assertThat(pluginOptions?.accuracyAlpha(), `is`(.5f)) - assertThat(pluginOptions?.accuracyColor(), `is`(Color.BLUE)) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun settingMapStyleImmediatelyBeforeLoadingPlugin_doesStillLoadLayersProperly() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - mapboxMap.setStyle(Style.LIGHT) - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - assertThat(plugin.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)) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayer_doesntShowUntilFirstLocationFix() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - - // 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 - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - // Check if the puck is visible - assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false)) - } - } - executePluginTest(pluginAction) - } - - // - // Location Layer Options - // - - @Test - fun locationLayerOptions_disablingStaleStateDoesWorkCorrectly() { - validateTestSetup() - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .staleStateTimeout(200) - .enableStaleState(false) - .build()) - - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - uiController.loopMainThreadForAtLeast(200) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { - it.forEach { - assertThat(it.getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) - } - } - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerOptions_loadsForegroundBitmapFromNameOption() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.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()) - - 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) - } - - plugin.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"))) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerOptions_loadsGpsNameWithGpsRenderMode() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .foregroundName("custom-foreground-bitmap") - .gpsName("custom-gps-bitmap") - .build()) - - plugin.renderMode = RenderMode.GPS - plugin.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"))) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerOptions_customIconNameRevertsToDefault() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .foregroundName("custom-foreground-bitmap") - .gpsName("custom-gps-bitmap") - .build()) - - plugin.renderMode = RenderMode.GPS - plugin.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"))) - - plugin.applyStyle(LocationLayerOptions.builder(context).build()) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - val revertedForegroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) - assertThat(revertedForegroundId, `is`(equalTo(FOREGROUND_ICON))) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun locationLayerOptions_customGpsIconNameChangeBackWithMode() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .gpsName("custom-gps-bitmap") - .build()) - - plugin.renderMode = RenderMode.GPS - plugin.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"))) - - plugin.renderMode = RenderMode.NORMAL - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - val revertedForegroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) - assertThat(revertedForegroundId, `is`(equalTo(FOREGROUND_ICON))) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun stillStaleAfterResuming() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .staleStateTimeout(200) - .build()) - - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - uiController.loopMainThreadForAtLeast(250) // engaging stale state - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) - - plugin.onStop() - plugin.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)) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun stillNotStaleAfterResuming() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) - - plugin.onStop() - plugin.onStart() - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) - assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun locationLayerOptions_accuracyRingWithColor() { - val color = Color.parseColor("#4A90E2") - val rgbaColor = ColorUtils.colorToRgbaString(color) - - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, - LocationLayerOptions.builder(context) - .accuracyColor(color) - .build()) - - plugin.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))) - } - } - } - } - - executePluginTest(pluginAction) - } - - @Test - fun forceLocationUpdate_doesMoveLocationLayerIconToCorrectPosition() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point - - assertThat(plugin.locationEngine, nullValue()) - assertEquals(point.latitude(), location.latitude, 0.1) - assertEquals(point.longitude(), location.longitude, 0.1) - } - } - executePluginTest(pluginAction) - } - - @Test - fun disablingPluginHidesPuck() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.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) - - plugin.deactivateLocationLayerPlugin() - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun disablingPluginAndChangingStyleAllowsToEnableAgain() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - plugin.deactivateLocationLayerPlugin() - mapboxMap.setStyle(Style.LIGHT) - - plugin.activateLocationLayerPlugin(context, false) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_isDisabledOnStart() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - assertThat(plugin.isLocationLayerEnabled, `is`(false)) - plugin.onStop() - plugin.onStart() - assertThat(plugin.isLocationLayerEnabled, `is`(false)) - plugin.activateLocationLayerPlugin(context, false) - assertThat(plugin.isLocationLayerEnabled, `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_keepsEnabledWhenStoppedAndStarted() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - assertThat(plugin.isLocationLayerEnabled, `is`(true)) - plugin.onStop() - plugin.onStart() - assertThat(plugin.isLocationLayerEnabled, `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_keepsDisabledWhenStoppedAndStarted() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.deactivateLocationLayerPlugin() - assertThat(plugin.isLocationLayerEnabled, `is`(false)) - plugin.onStop() - plugin.onStart() - assertThat(plugin.isLocationLayerEnabled, `is`(false)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_ableToChangeStyleAfterResuming() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - - plugin.onStop() - plugin.onStart() - - mapboxMap.setStyle(Style.DARK) - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_interruptedDuringStyleChange() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - mapboxMap.setStyle(Style.DARK) - plugin.onStop() - plugin.onStart() - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_forceLocationUpdateAfterStopped() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.onStop() - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE).isEmpty(), `is`(true)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_acceptAndReuseLocationUpdatesBeforeLayerStarted() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.onStop() - plugin.forceLocationUpdate(location) - plugin.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) - } - } - executePluginTest(pluginAction) - } - - @Test - fun lifecycle_lifecycleChangeRightAfterStyleReload() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.setStyle(Style.LIGHT) - plugin.onStop() - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - plugin.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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun mapChange_settingPluginStyle() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE) - val options = LocationLayerOptions.builder(context) - .accuracyColor(Color.RED) - .build() - - pushSourceUpdates(styleChangeIdlingResource) { - plugin.applyStyle(options) - } - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - } - } - executePluginTest(pluginAction) - - // Waiting for style to finish loading while pushing updates - onView(withId(R.id.content)).check(matches(isDisplayed())) - } - - @Test - fun mapChange_forcingLocation() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE) - - pushSourceUpdates(styleChangeIdlingResource) { - plugin.forceLocationUpdate(location) - } - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - } - } - executePluginTest(pluginAction) - - // Waiting for style to finish loading while pushing updates - onView(withId(R.id.content)).check(matches(isDisplayed())) - } - - @Test - fun mapChange_settingMapStyleBeforePluginCreation() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE) - plugin.activateLocationLayerPlugin(context, false) - - val options = LocationLayerOptions.builder(context) - .accuracyColor(Color.RED) - .build() - - pushSourceUpdates(styleChangeIdlingResource) { - plugin.forceLocationUpdate(location) - plugin.applyStyle(options) - } - } - } - executePluginTest(pluginAction) - - // Waiting for style to finish loading while pushing updates - onView(withId(R.id.content)).check(matches(isDisplayed())) - } - - @Test - fun animators_layerBearingCorrect() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.GPS - location.bearing = 77f - plugin.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 - plugin.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) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_cameraLatLngBearingCorrect() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING_GPS - location.bearing = 77f - plugin.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 - plugin.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) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_cameraBearingCorrect() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.NONE_GPS - val latitude = mapboxMap.cameraPosition.target.latitude - val longitude = mapboxMap.cameraPosition.target.longitude - - location.bearing = 77f - plugin.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 - plugin.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) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_cameraNoneCorrect() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.NONE - val latitude = mapboxMap.cameraPosition.target.latitude - val longitude = mapboxMap.cameraPosition.target.longitude - val bearing = mapboxMap.cameraPosition.bearing - - location.bearing = 77f - plugin.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 - plugin.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) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_focalPointAdjustment() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.cameraMode = CameraMode.NONE - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - assertThat(mapboxMap.uiSettings.focalPoint, nullValue()) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_dontZoomWhileNotTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.NONE - val zoom = mapboxMap.cameraPosition.zoom - plugin.zoomWhileTracking(10.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - - assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_zoomWhileTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.zoomWhileTracking(10.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - - assertEquals(10.0, mapboxMap.cameraPosition.zoom, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - @Ignore - fun animators_zoomWhileTrackingCanceledOnModeChange() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.zoomWhileTracking(15.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - plugin.cameraMode = CameraMode.NONE - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - - assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_dontZoomWhileStopped() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - - plugin.cameraMode = CameraMode.TRACKING - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - val zoom = mapboxMap.cameraPosition.zoom - - plugin.onStop() - plugin.zoomWhileTracking(10.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - - assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - @Ignore - fun animators_cancelZoomWhileTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.zoomWhileTracking(15.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - plugin.cancelZoomWhileTrackingAnimation() - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - - assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_dontTiltWhileNotTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.NONE - val tilt = mapboxMap.cameraPosition.tilt - plugin.tiltWhileTracking(30.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - - assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_tiltWhileTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.tiltWhileTracking(30.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - - assertEquals(30.0, mapboxMap.cameraPosition.tilt, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - @Ignore - fun animators_tiltWhileTrackingCanceledOnModeChange() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.tiltWhileTracking(30.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - plugin.cameraMode = CameraMode.NONE - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - - assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun animators_dontTiltWhileStopped() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - val tilt = mapboxMap.cameraPosition.tilt - - plugin.onStop() - plugin.tiltWhileTracking(30.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - - assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) - } - } - - executePluginTest(pluginAction) - } - - @Test - @Ignore - fun animators_cancelTiltWhileTracking() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING - plugin.tiltWhileTracking(30.0) - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - plugin.cancelTiltWhileTrackingAnimation() - uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - - assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun cameraPositionAdjustedToTrackingModeWhenPluginEnabled() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.cameraMode = CameraMode.TRACKING_GPS - plugin.forceLocationUpdate(location) - plugin.deactivateLocationLayerPlugin() - mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0))) - mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0)) - plugin.activateLocationLayerPlugin(context, false) - 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) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun compassEngine_onPluginInitializedDefaultIsProvided() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - assertTrue(plugin.compassEngine is LocationLayerCompassEngine) - } - } - - executePluginTest(pluginAction) - } - - @Test - fun compassEngine_changesWhenNewProvided() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - 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() { - } - } - - plugin.compassEngine = engine - assertThat(plugin.compassEngine, notNullValue()) - assertThat(plugin.compassEngine, `is`(equalTo(engine))) - } - } - - executePluginTest(pluginAction) - } - - @After - override fun afterTest() { - super.afterTest() - IdlingRegistry.getInstance().unregister(styleChangeIdlingResource) - } - - private fun executePluginTest(listener: LocationLayerPluginAction.OnPerformLocationLayerPluginAction) { - onView(withId(R.id.content)).perform(LocationLayerPluginAction(mapboxMap, listener)) - } -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt deleted file mode 100644 index a0f23ce485..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/locationlayer/LocationLayerTest.kt +++ /dev/null @@ -1,360 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.locationlayer - -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.maps.MapboxMap -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerConstants.* -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode -import com.mapbox.mapboxsdk.plugins.utils.* -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAPBOX_HEAVY_STYLE -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAP_CONNECTION_DELAY -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.MAP_RENDER_DELAY -import com.mapbox.mapboxsdk.plugins.utils.MapboxTestingUtils.Companion.pushSourceUpdates -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 LocationLayerTest : 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("test") - 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 pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.NORMAL - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - assertThat(mapboxMap.getSource(LOCATION_SOURCE), notNullValue()) - } - } - executePluginTest(pluginAction) - } - - // - // Location Layers - // - - @Test - fun renderModeNormal_trackingNormalLayersDoGetAdded() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.NORMAL - plugin.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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun renderModeCompass_bearingLayersDoGetAdded() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.COMPASS - plugin.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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun renderModeGps_navigationLayersDoGetAdded() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.GPS - plugin.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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun dontShowPuckWhenRenderModeSetAndPluginDisabled() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - plugin.deactivateLocationLayerPlugin() - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true) - plugin.renderMode = RenderMode.GPS - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - 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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun whenLocationLayerPluginDisabled_doesSetAllLayersToVisibilityNone() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.NORMAL - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - plugin.deactivateLocationLayerPlugin() - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER, shouldDisappear = true) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - // 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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun onMapChange_locationLayerLayersDoGetRedrawn() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.renderMode = RenderMode.NORMAL - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - mapboxMap.setStyleUrl(Style.LIGHT) - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - - assertThat(plugin.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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun whenStyleChanged_continuesUsingStaleIcons() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.applyStyle(LocationLayerOptions.builder(context).staleStateTimeout(100).build()) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - uiController.loopMainThreadForAtLeast(150) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - - assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `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)) - } - } - executePluginTest(pluginAction) - } - - @Test - fun whenStyleChanged_staleStateChanges() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.applyStyle(LocationLayerOptions.builder(context).staleStateTimeout(1).build()) - styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE) - pushSourceUpdates(styleChangeIdlingResource) { - plugin.forceLocationUpdate(location) - } - } - } - executePluginTest(pluginAction) - - // Waiting for style to finish loading while pushing updates - onView(withId(R.id.content)).check(matches(isDisplayed())) - } - - @Test - fun whenStyleChanged_layerVisibilityUpdates() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - styleChangeIdlingResource.waitForStyle((rule.activity as SingleActivity).mapView, mapboxMap, MAPBOX_HEAVY_STYLE) - var show = true - pushSourceUpdates(styleChangeIdlingResource) { - if (show) { - plugin.activateLocationLayerPlugin(context, false) - } else { - plugin.deactivateLocationLayerPlugin() - } - show = !show - } - - uiController.loopMainThreadForAtLeast(MAP_CONNECTION_DELAY) - } - } - executePluginTest(pluginAction) - - // Waiting for style to finish loading while pushing updates - onView(withId(R.id.content)).check(matches(isDisplayed())) - } - - @Test - fun accuracy_visibleWithNewLocation() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) - plugin.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) - } - } - executePluginTest(pluginAction) - } - - @Test - fun accuracy_visibleWhenCameraEased() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - plugin.forceLocationUpdate(location) - mapboxMap.waitForLayer(uiController, location, FOREGROUND_LAYER) - mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0), 300) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300) - - assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/, - mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0] - .getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f) - } - } - executePluginTest(pluginAction) - } - - @Test - fun accuracy_visibleWhenCameraMoved() { - val pluginAction = object : LocationLayerPluginAction.OnPerformLocationLayerPluginAction { - override fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, - uiController: UiController, context: Context) { - plugin.activateLocationLayerPlugin(context, false) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - plugin.forceLocationUpdate(location) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY) - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) - uiController.loopMainThreadForAtLeast(MAP_RENDER_DELAY + 300) - - assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/, - mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0] - .getNumberProperty(PROPERTY_ACCURACY_RADIUS).toFloat(), 0.1f) - } - } - executePluginTest(pluginAction) - } - - @After - override fun afterTest() { - super.afterTest() - IdlingRegistry.getInstance().unregister(styleChangeIdlingResource) - } - - private fun executePluginTest(listener: LocationLayerPluginAction.OnPerformLocationLayerPluginAction) { - onView(withId(R.id.content)).perform(LocationLayerPluginAction(mapboxMap, listener)) - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/LocationLayerPluginAction.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/LocationLayerPluginAction.kt deleted file mode 100644 index af2c9adf35..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/LocationLayerPluginAction.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.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.plugins.locationlayer.LocationLayerPlugin -import org.hamcrest.Matcher - -class LocationLayerPluginAction(private val mapboxMap: MapboxMap, - private val onPerformLocationLayerPluginAction: OnPerformLocationLayerPluginAction) : ViewAction { - - override fun getConstraints(): Matcher { - return isDisplayed() - } - - override fun getDescription(): String { - return javaClass.simpleName - } - - override fun perform(uiController: UiController, view: View) { - val plugin = mapboxMap.locationLayerPlugin - - while (mapboxMap.getSource("mapbox-location-source") == null) { - uiController.loopMainThreadForAtLeast(MapboxTestingUtils.MAP_RENDER_DELAY) - } - - onPerformLocationLayerPluginAction.onLocationLayerPluginAction( - plugin, - mapboxMap, - uiController, - view.context) - } - - interface OnPerformLocationLayerPluginAction { - fun onLocationLayerPluginAction(plugin: LocationLayerPlugin, mapboxMap: MapboxMap, uiController: UiController, context: Context) - } -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/MapboxTestingUtils.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/MapboxTestingUtils.kt deleted file mode 100644 index b77ab127d9..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/MapboxTestingUtils.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.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 { - return this.getSourceAs(sourceId)?.querySourceFeatures(null) ?: emptyList() -} - -fun MapboxMap.queryRenderedFeatures(location: Location, layerId: String): List { - 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++ - } -} - - -class MapboxTestingUtils { - companion object { - - const val MAP_RENDER_DELAY = 250L - const val MAP_CONNECTION_DELAY = 1000L - const val RENDER_TIMEOUT = 3_000L - - /** - * 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/plugins/utils/OnMapFragmentReadyIdlingResource.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapFragmentReadyIdlingResource.kt deleted file mode 100644 index fa6b732770..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapFragmentReadyIdlingResource.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.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/plugins/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapReadyIdlingResource.java deleted file mode 100644 index f084343594..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/OnMapReadyIdlingResource.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.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/plugins/utils/StyleChangeIdlingResource.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/StyleChangeIdlingResource.kt deleted file mode 100644 index ab2c855c65..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/plugins/utils/StyleChangeIdlingResource.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbox.mapboxsdk.plugins.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/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 8597a9ac14..a0594d8b83 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -816,7 +816,7 @@ android:value="com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity" /> ?) { + Toast.makeText(this@LocationFragmentActivity, "You need to accept location permissions.", + Toast.LENGTH_SHORT).show() + } + + override fun onPermissionResult(granted: Boolean) { + if (granted) { + if (savedInstanceState == null) { + fragmentManager + .beginTransaction() + .replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG) + .commit() + } + } else { + finish() + } + } + }) + permissionsManager.requestLocationPermissions(this) + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults) + } + + class LocationFragment : Fragment(), LocationEngineListener { + companion object { + const val TAG = "LFragment" + fun newInstance(): LocationFragment { + return LocationFragment() + } + } + + private lateinit var mapView: MapView + private lateinit var mapboxMap: MapboxMap + private var component: LocationComponent? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + mapView = MapView(inflater.context) + return mapView + } + + @SuppressLint("MissingPermission") + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + mapView.onCreate(savedInstanceState) + mapView.getMapAsync { + mapboxMap = it + component = mapboxMap.locationComponent + component?.activateLocationComponent(activity) + component?.locationEngine?.addLocationEngineListener(this) + } + } + + override fun onLocationChanged(location: Location?) { + if (location != null) { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 12.0)) + component?.locationEngine?.removeLocationEngineListener(this) + } + } + + override fun onConnected() { + // no impl + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + override fun onDestroyView() { + super.onDestroyView() + mapView.onDestroy() + component?.locationEngine?.removeLocationEngineListener(this) + } + } + + class EmptyFragment : Fragment() { + companion object { + const val TAG = "EmptyFragment" + fun newInstance(): EmptyFragment { + return EmptyFragment() + } + } + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View { + val textView = TextView(inflater?.context) + textView.text = "This is an empty Fragment" + return textView + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerFragmentActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerFragmentActivity.kt deleted file mode 100644 index fa2c84ab92..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerFragmentActivity.kt +++ /dev/null @@ -1,171 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.location - -import android.annotation.SuppressLint -import android.app.Fragment -import android.location.Location -import android.os.Bundle -import android.support.v7.app.AppCompatActivity -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import android.widget.Toast -import com.mapbox.android.core.location.LocationEngineListener -import com.mapbox.android.core.permissions.PermissionsListener -import com.mapbox.android.core.permissions.PermissionsManager -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory -import com.mapbox.mapboxsdk.geometry.LatLng -import com.mapbox.mapboxsdk.maps.MapView -import com.mapbox.mapboxsdk.maps.MapboxMap -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerPlugin -import com.mapbox.mapboxsdk.testapp.R -import kotlinx.android.synthetic.main.activity_location_layer_fragment.* - -class LocationLayerFragmentActivity : AppCompatActivity() { - private lateinit var permissionsManager: PermissionsManager - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_location_layer_fragment) - - fab.setOnClickListener { - val fragment = fragmentManager.findFragmentByTag(EmptyFragment.TAG) - if (fragment == null) { - fragmentManager - .beginTransaction() - .replace(R.id.container, EmptyFragment.newInstance(), EmptyFragment.TAG) - .addToBackStack("transaction2") - .commit() - } else { - this.onBackPressed() - } - } - supportActionBar?.setDisplayHomeAsUpEnabled(true) - - if (PermissionsManager.areLocationPermissionsGranted(this)) { - if (savedInstanceState == null) { - fragmentManager - .beginTransaction() - .replace(R.id.container, LocationLayerFragment.newInstance(), LocationLayerFragment.TAG) - .commit() - } - } else { - permissionsManager = PermissionsManager(object : PermissionsListener { - override fun onExplanationNeeded(permissionsToExplain: MutableList?) { - Toast.makeText(this@LocationLayerFragmentActivity, "You need to accept location permissions.", - Toast.LENGTH_SHORT).show() - } - - override fun onPermissionResult(granted: Boolean) { - if (granted) { - if (savedInstanceState == null) { - fragmentManager - .beginTransaction() - .replace(R.id.container, LocationLayerFragment.newInstance(), LocationLayerFragment.TAG) - .commit() - } - } else { - finish() - } - } - }) - permissionsManager.requestLocationPermissions(this) - } - } - - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults) - } - - class LocationLayerFragment : Fragment(), LocationEngineListener { - companion object { - const val TAG = "LLFragment" - fun newInstance(): LocationLayerFragment { - return LocationLayerFragment() - } - } - - private lateinit var mapView: MapView - private lateinit var mapboxMap: MapboxMap - private var plugin: LocationLayerPlugin? = null - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - mapView = MapView(inflater.context) - return mapView - } - - @SuppressLint("MissingPermission") - override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { - mapView.onCreate(savedInstanceState) - mapView.getMapAsync { - mapboxMap = it - plugin = mapboxMap.locationLayerPlugin - plugin?.activateLocationLayerPlugin(activity) - plugin?.locationEngine?.addLocationEngineListener(this) - } - } - - override fun onLocationChanged(location: Location?) { - if (location != null) { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 12.0)) - plugin?.locationEngine?.removeLocationEngineListener(this) - } - } - - override fun onConnected() { - // no impl - } - - override fun onStart() { - super.onStart() - mapView.onStart() - } - - override fun onResume() { - super.onResume() - mapView.onResume() - } - - override fun onPause() { - super.onPause() - mapView.onPause() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - mapView.onSaveInstanceState(outState) - } - - override fun onStop() { - super.onStop() - mapView.onStop() - } - - override fun onLowMemory() { - super.onLowMemory() - mapView.onLowMemory() - } - - override fun onDestroyView() { - super.onDestroyView() - mapView.onDestroy() - plugin?.locationEngine?.removeLocationEngineListener(this) - } - } - - class EmptyFragment : Fragment() { - companion object { - const val TAG = "EmptyFragment" - fun newInstance(): EmptyFragment { - return EmptyFragment() - } - } - - override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View { - val textView = TextView(inflater?.context) - textView.text = "This is an empty Fragment" - return textView - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerMapChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerMapChangeActivity.java deleted file mode 100644 index e59627d35e..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerMapChangeActivity.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.location; - -import android.annotation.SuppressLint; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.widget.Toast; - -import com.mapbox.android.core.permissions.PermissionsListener; -import com.mapbox.android.core.permissions.PermissionsManager; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerPlugin; -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode; -import com.mapbox.mapboxsdk.testapp.R; - -import java.util.List; - -public class LocationLayerMapChangeActivity extends AppCompatActivity implements OnMapReadyCallback { - - private MapView mapView; - private MapboxMap mapboxMap; - private PermissionsManager permissionsManager; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_location_layer_map_change); - - mapView = findViewById(R.id.mapView); - FloatingActionButton stylesFab = findViewById(R.id.fabStyles); - - stylesFab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mapboxMap != null) { - mapboxMap.setStyleUrl(Utils.getNextStyle()); - } - } - }); - - mapView.setStyleUrl(Utils.getNextStyle()); - mapView.onCreate(savedInstanceState); - - if (PermissionsManager.areLocationPermissionsGranted(this)) { - mapView.getMapAsync(this); - } else { - permissionsManager = new PermissionsManager(new PermissionsListener() { - @Override - public void onExplanationNeeded(List permissionsToExplain) { - Toast.makeText(LocationLayerMapChangeActivity.this, "You need to accept location permissions.", - Toast.LENGTH_SHORT).show(); - } - - @Override - public void onPermissionResult(boolean granted) { - if (granted) { - mapView.getMapAsync(LocationLayerMapChangeActivity.this); - } else { - finish(); - } - } - }); - permissionsManager.requestLocationPermissions(this); - } - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - @Override - public void onMapReady(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - activateLocationLayer(); - } - - @SuppressLint("MissingPermission") - private void activateLocationLayer() { - LocationLayerPlugin locationPlugin = mapboxMap.getLocationLayerPlugin(); - locationPlugin.activateLocationLayerPlugin(this); - locationPlugin.setRenderMode(RenderMode.COMPASS); - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerModesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerModesActivity.java deleted file mode 100644 index 4c8c8eda4b..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationLayerModesActivity.java +++ /dev/null @@ -1,383 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.location; - -import android.annotation.SuppressLint; -import android.content.res.Configuration; -import android.location.Location; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.ListPopupWindow; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.Toast; - -import com.mapbox.android.core.location.LocationEngine; -import com.mapbox.android.core.location.LocationEngineListener; -import com.mapbox.android.core.location.LocationEnginePriority; -import com.mapbox.android.core.location.LocationEngineProvider; -import com.mapbox.android.core.permissions.PermissionsListener; -import com.mapbox.android.core.permissions.PermissionsManager; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.constants.Style; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerOptions; -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerPlugin; -import com.mapbox.mapboxsdk.plugins.locationlayer.OnCameraTrackingChangedListener; -import com.mapbox.mapboxsdk.plugins.locationlayer.OnLocationLayerClickListener; -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.CameraMode; -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode; -import com.mapbox.mapboxsdk.testapp.R; - -import java.util.ArrayList; -import java.util.List; - -public class LocationLayerModesActivity extends AppCompatActivity implements OnMapReadyCallback, - LocationEngineListener, OnLocationLayerClickListener, OnCameraTrackingChangedListener { - - private MapView mapView; - private Button locationModeBtn; - private Button locationTrackingBtn; - - private PermissionsManager permissionsManager; - - private LocationLayerPlugin locationLayerPlugin; - private LocationEngine locationEngine; - private MapboxMap mapboxMap; - private boolean customStyle; - - private Bundle savedInstanceState; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_location_layer_mode); - - mapView = findViewById(R.id.mapView); - - locationModeBtn = findViewById(R.id.button_location_mode); - locationModeBtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (locationLayerPlugin == null) { - return; - } - showModeListDialog(); - } - }); - - locationTrackingBtn = findViewById(R.id.button_location_tracking); - locationTrackingBtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (locationLayerPlugin == null) { - return; - } - showTrackingListDialog(); - } - }); - - mapView.onCreate(savedInstanceState); - - if (PermissionsManager.areLocationPermissionsGranted(this)) { - mapView.getMapAsync(this); - } else { - permissionsManager = new PermissionsManager(new PermissionsListener() { - @Override - public void onExplanationNeeded(List permissionsToExplain) { - Toast.makeText(LocationLayerModesActivity.this, "You need to accept location permissions.", - Toast.LENGTH_SHORT).show(); - } - - @Override - public void onPermissionResult(boolean granted) { - if (granted) { - mapView.getMapAsync(LocationLayerModesActivity.this); - } else { - finish(); - } - } - }); - permissionsManager.requestLocationPermissions(this); - } - - this.savedInstanceState = savedInstanceState; - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - @SuppressLint("MissingPermission") - @Override - public void onMapReady(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - - locationEngine = new LocationEngineProvider(this).obtainBestLocationEngineAvailable(); - locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); - locationEngine.setFastestInterval(1000); - locationEngine.addLocationEngineListener(this); - locationEngine.activate(); - - locationLayerPlugin = mapboxMap.getLocationLayerPlugin(); - locationLayerPlugin.addOnLocationClickListener(this); - locationLayerPlugin.addOnCameraTrackingChangedListener(this); - - activateLocationLayer(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_location_mode, menu); - return true; - } - - @SuppressLint("MissingPermission") - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (locationLayerPlugin == null) { - return super.onOptionsItemSelected(item); - } - - int id = item.getItemId(); - if (id == R.id.action_style_change) { - toggleStyle(); - return true; - } else if (id == R.id.action_map_style_change) { - toggleMapStyle(); - return true; - } else if (id == R.id.action_plugin_disable) { - locationLayerPlugin.deactivateLocationLayerPlugin(); - return true; - } else if (id == R.id.action_plugin_enabled) { - activateLocationLayer(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - private void activateLocationLayer() { - if (locationLayerPlugin != null) { - int[] padding; - if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - padding = new int[] {0, 750, 0, 0}; - } else { - padding = new int[] {0, 250, 0, 0}; - } - - if (savedInstanceState == null) { - LocationLayerOptions options = LocationLayerOptions.builder(this) - .padding(padding) - .layerBelow("waterway-label") - .build(); - - locationLayerPlugin.activateLocationLayerPlugin(locationEngine, options); - } else { - LocationLayerOptions options = locationLayerPlugin - .getLocationLayerOptions() - .toBuilder() - .padding(padding) - .build(); - - locationLayerPlugin.setLocationEngine(locationEngine); - locationLayerPlugin.applyStyle(options); - } - } - } - - public void toggleStyle() { - customStyle = !customStyle; - locationLayerPlugin.applyStyle( - this, - customStyle ? R.style.CustomLocationLayer : R.style.mapbox_LocationLayer); - } - - public void toggleMapStyle() { - String styleUrl = mapboxMap.getStyleUrl().contentEquals(Style.DARK) ? Style.LIGHT : Style.DARK; - mapboxMap.setStyle(styleUrl); - } - - @Override - @SuppressWarnings( {"MissingPermission"}) - protected void onStart() { - super.onStart(); - mapView.onStart(); - if (locationEngine != null) { - locationEngine.addLocationEngineListener(this); - if (locationEngine.isConnected()) { - locationEngine.requestLocationUpdates(); - } else { - locationEngine.activate(); - } - } - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - if (locationEngine != null) { - locationEngine.removeLocationEngineListener(this); - locationEngine.removeLocationUpdates(); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - if (locationEngine != null) { - locationEngine.deactivate(); - } - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - - @Override - @SuppressWarnings( {"MissingPermission"}) - public void onConnected() { - locationEngine.requestLocationUpdates(); - } - - @Override - public void onLocationChanged(Location location) { - // no impl - } - - @Override - public void onLocationLayerClick() { - Toast.makeText(this, "OnLocationLayerClick", Toast.LENGTH_LONG).show(); - } - - private void showModeListDialog() { - List modes = new ArrayList<>(); - modes.add("Normal"); - modes.add("Compass"); - modes.add("GPS"); - ArrayAdapter profileAdapter = new ArrayAdapter<>(this, - android.R.layout.simple_list_item_1, modes); - ListPopupWindow listPopup = new ListPopupWindow(this); - listPopup.setAdapter(profileAdapter); - listPopup.setAnchorView(locationModeBtn); - listPopup.setOnItemClickListener((parent, itemView, position, id) -> { - String selectedMode = modes.get(position); - locationModeBtn.setText(selectedMode); - if (selectedMode.contentEquals("Normal")) { - setRendererMode(RenderMode.NORMAL); - } else if (selectedMode.contentEquals("Compass")) { - setRendererMode(RenderMode.COMPASS); - } else if (selectedMode.contentEquals("GPS")) { - setRendererMode(RenderMode.GPS); - } - listPopup.dismiss(); - }); - listPopup.show(); - } - - private void setRendererMode(@RenderMode.Mode int mode) { - locationLayerPlugin.setRenderMode(mode); - if (mode == RenderMode.NORMAL) { - locationModeBtn.setText("Normal"); - } else if (mode == RenderMode.COMPASS) { - locationModeBtn.setText("Compass"); - } else if (mode == RenderMode.GPS) { - locationModeBtn.setText("Gps"); - } - } - - private void showTrackingListDialog() { - List trackingTypes = new ArrayList<>(); - trackingTypes.add("None"); - trackingTypes.add("Tracking"); - trackingTypes.add("Tracking Compass"); - trackingTypes.add("Tracking GPS"); - trackingTypes.add("Tracking GPS North"); - ArrayAdapter profileAdapter = new ArrayAdapter<>(this, - android.R.layout.simple_list_item_1, trackingTypes); - ListPopupWindow listPopup = new ListPopupWindow(this); - listPopup.setAdapter(profileAdapter); - listPopup.setAnchorView(locationTrackingBtn); - listPopup.setOnItemClickListener((parent, itemView, position, id) -> { - String selectedTrackingType = trackingTypes.get(position); - locationTrackingBtn.setText(selectedTrackingType); - if (selectedTrackingType.contentEquals("None")) { - locationLayerPlugin.setCameraMode(CameraMode.NONE); - } else if (selectedTrackingType.contentEquals("Tracking")) { - locationLayerPlugin.setCameraMode(CameraMode.TRACKING); - } else if (selectedTrackingType.contentEquals("Tracking Compass")) { - locationLayerPlugin.setCameraMode(CameraMode.TRACKING_COMPASS); - } else if (selectedTrackingType.contentEquals("Tracking GPS")) { - locationLayerPlugin.setCameraMode(CameraMode.TRACKING_GPS); - } else if (selectedTrackingType.contentEquals("Tracking GPS North")) { - locationLayerPlugin.setCameraMode(CameraMode.TRACKING_GPS_NORTH); - } - listPopup.dismiss(); - - if (locationLayerPlugin.getCameraMode() != CameraMode.NONE) { - locationLayerPlugin.zoomWhileTracking(15, 750, new MapboxMap.CancelableCallback() { - @Override - public void onCancel() { - // No impl - } - - @Override - public void onFinish() { - locationLayerPlugin.tiltWhileTracking(45); - } - }); - } else { - mapboxMap.easeCamera(CameraUpdateFactory.tiltTo(0)); - } - }); - listPopup.show(); - } - - @Override - public void onCameraTrackingDismissed() { - locationTrackingBtn.setText("None"); - } - - @Override - public void onCameraTrackingChanged(int currentMode) { - if (currentMode == CameraMode.NONE) { - locationTrackingBtn.setText("None"); - } else if (currentMode == CameraMode.TRACKING) { - locationTrackingBtn.setText("Tracking"); - } else if (currentMode == CameraMode.TRACKING_COMPASS) { - locationTrackingBtn.setText("Tracking Compass"); - } else if (currentMode == CameraMode.TRACKING_GPS) { - locationTrackingBtn.setText("Tracking GPS"); - } else if (currentMode == CameraMode.TRACKING_GPS_NORTH) { - locationTrackingBtn.setText("Tracking GPS North"); - } - } -} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java new file mode 100644 index 0000000000..6fa514e28b --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationMapChangeActivity.java @@ -0,0 +1,131 @@ +package com.mapbox.mapboxsdk.testapp.activity.location; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.Toast; + +import com.mapbox.android.core.permissions.PermissionsListener; +import com.mapbox.android.core.permissions.PermissionsManager; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.List; + +public class LocationMapChangeActivity extends AppCompatActivity implements OnMapReadyCallback { + + private MapView mapView; + private MapboxMap mapboxMap; + private PermissionsManager permissionsManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_location_layer_map_change); + + mapView = findViewById(R.id.mapView); + FloatingActionButton stylesFab = findViewById(R.id.fabStyles); + + stylesFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mapboxMap != null) { + mapboxMap.setStyleUrl(Utils.getNextStyle()); + } + } + }); + + mapView.setStyleUrl(Utils.getNextStyle()); + mapView.onCreate(savedInstanceState); + + if (PermissionsManager.areLocationPermissionsGranted(this)) { + mapView.getMapAsync(this); + } else { + permissionsManager = new PermissionsManager(new PermissionsListener() { + @Override + public void onExplanationNeeded(List permissionsToExplain) { + Toast.makeText(LocationMapChangeActivity.this, "You need to accept location permissions.", + Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean granted) { + if (granted) { + mapView.getMapAsync(LocationMapChangeActivity.this); + } else { + finish(); + } + } + }); + permissionsManager.requestLocationPermissions(this); + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + public void onMapReady(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + activateLocationComponent(); + } + + @SuppressLint("MissingPermission") + private void activateLocationComponent() { + LocationComponent locationComponent = mapboxMap.getLocationComponent(); + locationComponent.activateLocationComponent(this); + locationComponent.setRenderMode(RenderMode.COMPASS); + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java new file mode 100644 index 0000000000..f2f57c854d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationModesActivity.java @@ -0,0 +1,383 @@ +package com.mapbox.mapboxsdk.testapp.activity.location; + +import android.annotation.SuppressLint; +import android.content.res.Configuration; +import android.location.Location; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.ListPopupWindow; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Toast; + +import com.mapbox.android.core.location.LocationEngine; +import com.mapbox.android.core.location.LocationEngineListener; +import com.mapbox.android.core.location.LocationEnginePriority; +import com.mapbox.android.core.location.LocationEngineProvider; +import com.mapbox.android.core.permissions.PermissionsListener; +import com.mapbox.android.core.permissions.PermissionsManager; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.location.LocationComponentOptions; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener; +import com.mapbox.mapboxsdk.location.OnLocationComponentClickListener; +import com.mapbox.mapboxsdk.location.modes.CameraMode; +import com.mapbox.mapboxsdk.location.modes.RenderMode; +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.ArrayList; +import java.util.List; + +public class LocationModesActivity extends AppCompatActivity implements OnMapReadyCallback, + LocationEngineListener, OnLocationComponentClickListener, OnCameraTrackingChangedListener { + + private MapView mapView; + private Button locationModeBtn; + private Button locationTrackingBtn; + + private PermissionsManager permissionsManager; + + private LocationComponent locationComponent; + private LocationEngine locationEngine; + private MapboxMap mapboxMap; + private boolean customStyle; + + private Bundle savedInstanceState; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_location_layer_mode); + + mapView = findViewById(R.id.mapView); + + locationModeBtn = findViewById(R.id.button_location_mode); + locationModeBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (locationComponent == null) { + return; + } + showModeListDialog(); + } + }); + + locationTrackingBtn = findViewById(R.id.button_location_tracking); + locationTrackingBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (locationComponent == null) { + return; + } + showTrackingListDialog(); + } + }); + + mapView.onCreate(savedInstanceState); + + if (PermissionsManager.areLocationPermissionsGranted(this)) { + mapView.getMapAsync(this); + } else { + permissionsManager = new PermissionsManager(new PermissionsListener() { + @Override + public void onExplanationNeeded(List permissionsToExplain) { + Toast.makeText(LocationModesActivity.this, "You need to accept location permissions.", + Toast.LENGTH_SHORT).show(); + } + + @Override + public void onPermissionResult(boolean granted) { + if (granted) { + mapView.getMapAsync(LocationModesActivity.this); + } else { + finish(); + } + } + }); + permissionsManager.requestLocationPermissions(this); + } + + this.savedInstanceState = savedInstanceState; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @SuppressLint("MissingPermission") + @Override + public void onMapReady(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + + locationEngine = new LocationEngineProvider(this).obtainBestLocationEngineAvailable(); + locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); + locationEngine.setFastestInterval(1000); + locationEngine.addLocationEngineListener(this); + locationEngine.activate(); + + locationComponent = mapboxMap.getLocationComponent(); + locationComponent.addOnLocationClickListener(this); + locationComponent.addOnCameraTrackingChangedListener(this); + + activateLocationComponent(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_location_mode, menu); + return true; + } + + @SuppressLint("MissingPermission") + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (locationComponent == null) { + return super.onOptionsItemSelected(item); + } + + int id = item.getItemId(); + if (id == R.id.action_style_change) { + toggleStyle(); + return true; + } else if (id == R.id.action_map_style_change) { + toggleMapStyle(); + return true; + } else if (id == R.id.action_component_disable) { + locationComponent.deactivateLocationComponent(); + return true; + } else if (id == R.id.action_component_enabled) { + activateLocationComponent(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void activateLocationComponent() { + if (locationComponent != null) { + int[] padding; + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + padding = new int[] {0, 750, 0, 0}; + } else { + padding = new int[] {0, 250, 0, 0}; + } + + if (savedInstanceState == null) { + LocationComponentOptions options = LocationComponentOptions.builder(this) + .padding(padding) + .layerBelow("waterway-label") + .build(); + + locationComponent.activateLocationComponent(locationEngine, options); + } else { + LocationComponentOptions options = locationComponent + .getLocationComponentOptions() + .toBuilder() + .padding(padding) + .build(); + + locationComponent.setLocationEngine(locationEngine); + locationComponent.applyStyle(options); + } + } + } + + public void toggleStyle() { + customStyle = !customStyle; + locationComponent.applyStyle( + this, + customStyle ? R.style.CustomLocationComponent : R.style.mapbox_LocationComponent); + } + + public void toggleMapStyle() { + String styleUrl = mapboxMap.getStyleUrl().contentEquals(Style.DARK) ? Style.LIGHT : Style.DARK; + mapboxMap.setStyle(styleUrl); + } + + @Override + @SuppressWarnings( {"MissingPermission"}) + protected void onStart() { + super.onStart(); + mapView.onStart(); + if (locationEngine != null) { + locationEngine.addLocationEngineListener(this); + if (locationEngine.isConnected()) { + locationEngine.requestLocationUpdates(); + } else { + locationEngine.activate(); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + if (locationEngine != null) { + locationEngine.removeLocationEngineListener(this); + locationEngine.removeLocationUpdates(); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + if (locationEngine != null) { + locationEngine.deactivate(); + } + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + @SuppressWarnings( {"MissingPermission"}) + public void onConnected() { + locationEngine.requestLocationUpdates(); + } + + @Override + public void onLocationChanged(Location location) { + // no impl + } + + @Override + public void onLocationComponentClick() { + Toast.makeText(this, "OnlocationComponentClick", Toast.LENGTH_LONG).show(); + } + + private void showModeListDialog() { + List modes = new ArrayList<>(); + modes.add("Normal"); + modes.add("Compass"); + modes.add("GPS"); + ArrayAdapter profileAdapter = new ArrayAdapter<>(this, + android.R.layout.simple_list_item_1, modes); + ListPopupWindow listPopup = new ListPopupWindow(this); + listPopup.setAdapter(profileAdapter); + listPopup.setAnchorView(locationModeBtn); + listPopup.setOnItemClickListener((parent, itemView, position, id) -> { + String selectedMode = modes.get(position); + locationModeBtn.setText(selectedMode); + if (selectedMode.contentEquals("Normal")) { + setRendererMode(RenderMode.NORMAL); + } else if (selectedMode.contentEquals("Compass")) { + setRendererMode(RenderMode.COMPASS); + } else if (selectedMode.contentEquals("GPS")) { + setRendererMode(RenderMode.GPS); + } + listPopup.dismiss(); + }); + listPopup.show(); + } + + private void setRendererMode(@RenderMode.Mode int mode) { + locationComponent.setRenderMode(mode); + if (mode == RenderMode.NORMAL) { + locationModeBtn.setText("Normal"); + } else if (mode == RenderMode.COMPASS) { + locationModeBtn.setText("Compass"); + } else if (mode == RenderMode.GPS) { + locationModeBtn.setText("Gps"); + } + } + + private void showTrackingListDialog() { + List trackingTypes = new ArrayList<>(); + trackingTypes.add("None"); + trackingTypes.add("Tracking"); + trackingTypes.add("Tracking Compass"); + trackingTypes.add("Tracking GPS"); + trackingTypes.add("Tracking GPS North"); + ArrayAdapter profileAdapter = new ArrayAdapter<>(this, + android.R.layout.simple_list_item_1, trackingTypes); + ListPopupWindow listPopup = new ListPopupWindow(this); + listPopup.setAdapter(profileAdapter); + listPopup.setAnchorView(locationTrackingBtn); + listPopup.setOnItemClickListener((parent, itemView, position, id) -> { + String selectedTrackingType = trackingTypes.get(position); + locationTrackingBtn.setText(selectedTrackingType); + if (selectedTrackingType.contentEquals("None")) { + locationComponent.setCameraMode(CameraMode.NONE); + } else if (selectedTrackingType.contentEquals("Tracking")) { + locationComponent.setCameraMode(CameraMode.TRACKING); + } else if (selectedTrackingType.contentEquals("Tracking Compass")) { + locationComponent.setCameraMode(CameraMode.TRACKING_COMPASS); + } else if (selectedTrackingType.contentEquals("Tracking GPS")) { + locationComponent.setCameraMode(CameraMode.TRACKING_GPS); + } else if (selectedTrackingType.contentEquals("Tracking GPS North")) { + locationComponent.setCameraMode(CameraMode.TRACKING_GPS_NORTH); + } + listPopup.dismiss(); + + if (locationComponent.getCameraMode() != CameraMode.NONE) { + locationComponent.zoomWhileTracking(15, 750, new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + // No impl + } + + @Override + public void onFinish() { + locationComponent.tiltWhileTracking(45); + } + }); + } else { + mapboxMap.easeCamera(CameraUpdateFactory.tiltTo(0)); + } + }); + listPopup.show(); + } + + @Override + public void onCameraTrackingDismissed() { + locationTrackingBtn.setText("None"); + } + + @Override + public void onCameraTrackingChanged(int currentMode) { + if (currentMode == CameraMode.NONE) { + locationTrackingBtn.setText("None"); + } else if (currentMode == CameraMode.TRACKING) { + locationTrackingBtn.setText("Tracking"); + } else if (currentMode == CameraMode.TRACKING_COMPASS) { + locationTrackingBtn.setText("Tracking Compass"); + } else if (currentMode == CameraMode.TRACKING_GPS) { + locationTrackingBtn.setText("Tracking GPS"); + } else if (currentMode == CameraMode.TRACKING_GPS_NORTH) { + locationTrackingBtn.setText("Tracking GPS North"); + } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java index 3e9f0853ea..5750e97d63 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/ManualLocationUpdatesActivity.java @@ -18,8 +18,8 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.plugins.locationlayer.LocationLayerPlugin; -import com.mapbox.mapboxsdk.plugins.locationlayer.modes.RenderMode; +import com.mapbox.mapboxsdk.location.LocationComponent; +import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.testapp.R; import java.util.List; @@ -30,7 +30,7 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements LocationEngineListener { private MapView mapView; - private LocationLayerPlugin locationLayerPlugin; + private LocationComponent locationComponent; private LocationEngine locationEngine; private PermissionsManager permissionsManager; @@ -43,8 +43,8 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements fabManualUpdate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (locationLayerPlugin != null && locationLayerPlugin.getLocationEngine() == null) { - locationLayerPlugin.forceLocationUpdate( + if (locationComponent != null && locationComponent.getLocationEngine() == null) { + locationComponent.forceLocationUpdate( Utils.getRandomLocation(LatLngBounds.from(60, 25, 40, -5))); } } @@ -55,11 +55,11 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements fabToggle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (locationLayerPlugin != null) { - locationLayerPlugin.setLocationEngine(locationLayerPlugin.getLocationEngine() == null ? locationEngine : + if (locationComponent != null) { + locationComponent.setLocationEngine(locationComponent.getLocationEngine() == null ? locationEngine : null); - if (locationLayerPlugin.getLocationEngine() == null) { + if (locationComponent.getLocationEngine() == null) { fabToggle.setImageResource(R.drawable.ic_layers_clear); fabManualUpdate.setEnabled(true); fabManualUpdate.setAlpha(1f); @@ -118,9 +118,9 @@ public class ManualLocationUpdatesActivity extends AppCompatActivity implements locationEngine.addLocationEngineListener(this); locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY); locationEngine.activate(); - locationLayerPlugin = mapboxMap.getLocationLayerPlugin(); - locationLayerPlugin.activateLocationLayerPlugin(this, locationEngine); - locationLayerPlugin.setRenderMode(RenderMode.COMPASS); + locationComponent = mapboxMap.getLocationComponent(); + locationComponent.activateLocationComponent(this, locationEngine); + locationComponent.setRenderMode(RenderMode.COMPASS); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_mode.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_mode.xml index 7ce217ecd9..7004999f88 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_mode.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_location_mode.xml @@ -9,12 +9,12 @@ android:title="Toggle custom Map style" app:showAsAction="never"/> - - \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 05035760f9..cb9c2043dc 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -73,6 +73,6 @@ Click to add a marker, long-click to drag Change map\'s style while location is displayed Showcases location render and tracking modes - Uses LocationLayer in a Fragment + Uses LocationComponent in a Fragment Force location updates and don\'t rely on the engine diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml index facc169299..a0525171a5 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml @@ -38,7 +38,7 @@