Rename Gradle targets Android (#2226)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-sdk tools:overrideLibrary="android_libs.ub_uiautomator"/>
|
||||
</manifest>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
package org.maplibre.android
|
||||
|
||||
import com.microsoft.appcenter.espresso.Factory
|
||||
import org.junit.After
|
||||
import org.junit.Rule
|
||||
|
||||
abstract class AppCenter {
|
||||
@get:Rule
|
||||
var reportHelper = Factory.getReportHelper()!!
|
||||
|
||||
@After
|
||||
open fun afterTest() {
|
||||
reportHelper.label(javaClass.simpleName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.maplibre.android
|
||||
|
||||
import org.maplibre.android.testapp.MapLibreApplication
|
||||
|
||||
class InstrumentationApplication : MapLibreApplication() {
|
||||
fun initializeLeakCanary(): Boolean {
|
||||
// do not initialize leak canary during instrumentation tests
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.maplibre.android
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.test.runner.AndroidJUnitRunner
|
||||
|
||||
class InstrumentationRunner : AndroidJUnitRunner() {
|
||||
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
|
||||
return super.newApplication(cl, InstrumentationApplication::class.java.name, context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.maplibre.android.benchmark
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.maplibre.android.testapp.activity.benchmark.BenchmarkActivity
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class Benchmark {
|
||||
@Test
|
||||
fun worldTourBenchmark() {
|
||||
val scenario = ActivityScenario.launchActivityForResult(BenchmarkActivity::class.java)
|
||||
while (scenario.state !== Lifecycle.State.DESTROYED) {
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
assertEquals(scenario.result.resultCode, Activity.RESULT_OK)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package org.maplibre.android.camera
|
||||
|
||||
import android.graphics.PointF
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.geometry.LatLngBounds
|
||||
import org.maplibre.android.testapp.activity.BaseTest
|
||||
import org.maplibre.android.testapp.activity.espresso.DeviceIndependentTestActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class CameraUpdateFactoryTest : BaseTest() {
|
||||
|
||||
override fun getActivityClass(): Class<*> {
|
||||
return DeviceIndependentTestActivity::class.java
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngBoundsUntiltedUnrotated() {
|
||||
maplibreMap.cameraPosition = CameraPosition.Builder()
|
||||
.target(LatLng(60.0, 24.0))
|
||||
.bearing(0.0)
|
||||
.tilt(0.0)
|
||||
.build()
|
||||
|
||||
val bounds: LatLngBounds = LatLngBounds.Builder()
|
||||
.include(LatLng(62.0, 26.0))
|
||||
.include(LatLng(58.0, 22.0))
|
||||
.build()
|
||||
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
|
||||
|
||||
val cameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals("latitude should match:", 60.0, cameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals("longitude should match:", 24.0, cameraPosition.target!!.longitude, 0.1)
|
||||
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
|
||||
assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
|
||||
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngBoundsTilted() {
|
||||
maplibreMap.cameraPosition = CameraPosition.Builder()
|
||||
.target(LatLng(60.0, 24.0))
|
||||
.bearing(0.0)
|
||||
.tilt(45.0)
|
||||
.build()
|
||||
|
||||
val bounds: LatLngBounds = LatLngBounds.Builder()
|
||||
.include(LatLng(62.0, 26.0))
|
||||
.include(LatLng(58.0, 22.0))
|
||||
.build()
|
||||
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
|
||||
|
||||
val cameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals("latitude should match:", 60.0, cameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals("longitude should match:", 24.0, cameraPosition.target!!.longitude, 0.1)
|
||||
assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
|
||||
assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
|
||||
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngBoundsRotated() {
|
||||
maplibreMap.cameraPosition = CameraPosition.Builder()
|
||||
.target(LatLng(60.0, 24.0))
|
||||
.bearing(30.0)
|
||||
.tilt(0.0)
|
||||
.build()
|
||||
|
||||
val bounds: LatLngBounds = LatLngBounds.Builder()
|
||||
.include(LatLng(62.0, 26.0))
|
||||
.include(LatLng(58.0, 22.0))
|
||||
.build()
|
||||
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
|
||||
|
||||
val cameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals("latitude should match:", 60.0, cameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals("longitude should match:", 24.0, cameraPosition.target!!.longitude, 0.1)
|
||||
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
|
||||
assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
|
||||
assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngBoundsTiltedRotated() {
|
||||
maplibreMap.cameraPosition = CameraPosition.Builder()
|
||||
.target(LatLng(60.0, 24.0))
|
||||
.bearing(30.0)
|
||||
.tilt(45.0)
|
||||
.build()
|
||||
|
||||
val bounds: LatLngBounds = LatLngBounds.Builder()
|
||||
.include(LatLng(62.0, 26.0))
|
||||
.include(LatLng(58.0, 22.0))
|
||||
.build()
|
||||
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
|
||||
|
||||
val cameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals("latitude should match:", 60.0, cameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals("longitude should match:", 24.0, cameraPosition.target!!.longitude, 0.1)
|
||||
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
|
||||
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
|
||||
assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngBoundsWithProvidedTiltAndRotation() {
|
||||
maplibreMap.cameraPosition = CameraPosition.Builder()
|
||||
.target(LatLng(60.0, 24.0))
|
||||
.bearing(0.0)
|
||||
.tilt(0.0)
|
||||
.build()
|
||||
|
||||
val bounds: LatLngBounds = LatLngBounds.Builder()
|
||||
.include(LatLng(62.0, 26.0))
|
||||
.include(LatLng(58.0, 22.0))
|
||||
.build()
|
||||
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
|
||||
|
||||
val cameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals("latitude should match:", 60.0, cameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals("longitude should match:", 24.0, cameraPosition.target!!.longitude, 0.1)
|
||||
assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
|
||||
assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
|
||||
assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun withPadding_cameraInvalidated_paddingPersisting() {
|
||||
val initialCameraPosition = maplibreMap.cameraPosition
|
||||
val initialPoint = maplibreMap.projection.toScreenLocation(initialCameraPosition.target!!)
|
||||
|
||||
val bottomPadding = mapView.height / 4
|
||||
val leftPadding = mapView.width / 4
|
||||
val padding = doubleArrayOf(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble())
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.paddingTo(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble()))
|
||||
|
||||
Assert.assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), maplibreMap.padding)
|
||||
|
||||
val resultingCameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals(initialCameraPosition.target!!, resultingCameraPosition.target!!)
|
||||
assertEquals(
|
||||
PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
|
||||
maplibreMap.projection.toScreenLocation(resultingCameraPosition.target!!)
|
||||
)
|
||||
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun withLatLngPadding_cameraInvalidated_paddingPersisting() {
|
||||
val expectedTarget = LatLng(2.0, 2.0)
|
||||
|
||||
val topPadding = mapView.height / 4
|
||||
val rightPadding = mapView.width / 4
|
||||
val padding = doubleArrayOf(0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0)
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngPadding(expectedTarget, 0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0))
|
||||
|
||||
Assert.assertArrayEquals(intArrayOf(0, topPadding, rightPadding, 0), maplibreMap.padding)
|
||||
|
||||
val resultingCameraPosition = maplibreMap.cameraPosition
|
||||
assertEquals(expectedTarget.latitude, resultingCameraPosition.target!!.latitude, 0.1)
|
||||
assertEquals(expectedTarget!!.longitude, resultingCameraPosition.target!!.longitude, 0.1)
|
||||
|
||||
val centerLatLng = maplibreMap.projection.fromScreenLocation(PointF((mapView.width / 2).toFloat(), (mapView.height / 2).toFloat()))
|
||||
assertTrue(centerLatLng.latitude > resultingCameraPosition.target!!.latitude)
|
||||
assertTrue(centerLatLng.longitude > resultingCameraPosition.target!!.longitude)
|
||||
Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.*
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.junit.Before
|
||||
|
||||
const val TIMEOUT_UI_SEARCH_WAIT = 5000L
|
||||
|
||||
abstract class BaseIntegrationTest : AppCenter() {
|
||||
|
||||
protected lateinit var device: UiDevice
|
||||
|
||||
@Before
|
||||
open fun beforeTest() {
|
||||
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches an activity with FLAG_ACTIVITY_NEW_TASK.
|
||||
* <p>
|
||||
* To resume an activity, you need to add a single instance launchmode to your manifest configuration.
|
||||
* <p>
|
||||
*/
|
||||
fun UiDevice.launchActivity(context: Context, clazz: Class<*>) {
|
||||
val applicationPackage = InstrumentationRegistry.getInstrumentation().targetContext.packageName
|
||||
val intent = Intent(context, clazz)
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
InstrumentationRegistry.getInstrumentation().context.startActivity(intent)
|
||||
wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT)
|
||||
}
|
||||
|
||||
fun UiDevice.scrollRecyclerViewTo(recycleItem: String) {
|
||||
val appView = UiScrollable(UiSelector().scrollable(true))
|
||||
appView.scrollIntoView(UiSelector().text(recycleItem))
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import androidx.test.uiautomator.UiSelector
|
||||
import org.maplibre.android.testapp.activity.fragment.FragmentBackStackActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates MapFragment integration on the backstack
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class FragmentBackStackTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun backPressedOnBackStackResumed() {
|
||||
device.waitForIdle()
|
||||
clickReplaceFragmentButton()
|
||||
device.pressHome()
|
||||
device.waitForIdle()
|
||||
device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java)
|
||||
backPressBackStack()
|
||||
device.waitForIdle()
|
||||
}
|
||||
|
||||
private fun clickReplaceFragmentButton() {
|
||||
device.findObject(UiSelector().description(textDescription)).click()
|
||||
}
|
||||
|
||||
private fun backPressBackStack() {
|
||||
device.pressBack() // pops fragment, showing map
|
||||
device.pressBack() // finish activity
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val textDescription = "btn_change_fragment"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.maplayout.SimpleMapActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates reopening an Activity with a GLSurfaceView
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class GLSurfaceViewReopenTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun reopenSimpleMapActivity() {
|
||||
device.waitForIdle()
|
||||
device.pressHome()
|
||||
device.waitForIdle()
|
||||
device.launchActivity(activityRule.activity, SimpleMapActivity::class.java)
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates if a GLSurfaceView surface can be recreated without crashing.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class GLSurfaceViewReuseTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun scrollRecyclerView() {
|
||||
device.waitForIdle()
|
||||
device.scrollRecyclerViewTo("Twenty-one")
|
||||
device.waitForIdle()
|
||||
device.scrollRecyclerViewTo("One")
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.maplayout.SimpleMapActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class OrientationChangeTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun rotateSimpleMap() {
|
||||
device.setOrientationLeft()
|
||||
device.waitForIdle()
|
||||
device.setOrientationNatural()
|
||||
device.waitForIdle()
|
||||
device.setOrientationRight()
|
||||
device.waitForIdle()
|
||||
device.setOrientationNatural()
|
||||
device.setOrientationLeft()
|
||||
device.setOrientationNatural()
|
||||
device.setOrientationRight()
|
||||
device.setOrientationNatural()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.feature.QueryRenderedFeaturesBoxCountActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates reopening an Activity and querying the map before surface recreation #14394
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class QueryRenderedFeaturesBoxCountTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<QueryRenderedFeaturesBoxCountActivity> =
|
||||
ActivityTestRule(QueryRenderedFeaturesBoxCountActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun reopenQueryRendererFeaturesActivity() {
|
||||
device.waitForIdle()
|
||||
device.pressHome()
|
||||
device.waitForIdle()
|
||||
device.launchActivity(activityRule.activity, QueryRenderedFeaturesBoxCountActivity::class.java)
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.textureview.TextureViewDebugModeActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates reopening an Activity with a TextureView
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class TextureViewReopenTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun reopenTextureViewDebugActivity() {
|
||||
device.waitForIdle()
|
||||
device.pressHome()
|
||||
device.waitForIdle()
|
||||
device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java)
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.testapp.activity.maplayout.TextureRecyclerViewActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates if a GLSurfaceView surface can be recreated without crashing.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class TextureViewReuseTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun scrollRecyclerView() {
|
||||
device.waitForIdle()
|
||||
device.scrollRecyclerViewTo("Twenty-one")
|
||||
device.waitForIdle()
|
||||
device.scrollRecyclerViewTo("One")
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.maplibre.android.integration
|
||||
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import androidx.test.uiautomator.UiSelector
|
||||
import org.maplibre.android.testapp.activity.fragment.ViewPagerActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates MapFragment integration with a ViewPager
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class ViewPagerScrollTest : BaseIntegrationTest() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java)
|
||||
|
||||
@Test
|
||||
@LargeTest
|
||||
fun scrollViewPager() {
|
||||
for (i in 1..4) {
|
||||
clickTab(i)
|
||||
}
|
||||
|
||||
for (i in 3 downTo 0) {
|
||||
clickTab(i)
|
||||
}
|
||||
}
|
||||
|
||||
private fun clickTab(index: Int) {
|
||||
device.findObject(UiSelector().text("Page $index")).click()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,351 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.location;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.location.LocationPropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for LocationIndicatorLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class LocationIndicatorLayerTest extends BaseLayerTest {
|
||||
|
||||
private LocationIndicatorLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new LocationIndicatorLayer("my-layer");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testTopImageAsConstant() {
|
||||
Timber.i("top-image");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getTopImage().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "undefined";
|
||||
layer.setProperties(topImage(propertyValue));
|
||||
assertEquals(layer.getTopImage().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBearingImageAsConstant() {
|
||||
Timber.i("bearing-image");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBearingImage().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "undefined";
|
||||
layer.setProperties(bearingImage(propertyValue));
|
||||
assertEquals(layer.getBearingImage().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testShadowImageAsConstant() {
|
||||
Timber.i("shadow-image");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getShadowImage().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "undefined";
|
||||
layer.setProperties(shadowImage(propertyValue));
|
||||
assertEquals(layer.getShadowImage().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testPerspectiveCompensationAsConstant() {
|
||||
Timber.i("perspective-compensation");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getPerspectiveCompensation().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(perspectiveCompensation(propertyValue));
|
||||
assertEquals(layer.getPerspectiveCompensation().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testImageTiltDisplacementAsConstant() {
|
||||
Timber.i("image-tilt-displacement");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getImageTiltDisplacement().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(imageTiltDisplacement(propertyValue));
|
||||
assertEquals(layer.getImageTiltDisplacement().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBearingAsConstant() {
|
||||
Timber.i("bearing");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBearing().getValue());
|
||||
|
||||
// Set and Get
|
||||
Double propertyValue = 0.3;
|
||||
layer.setProperties(bearing(propertyValue));
|
||||
assertEquals(layer.getBearing().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLocationTransition() {
|
||||
Timber.i("locationTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLocationTransition(options);
|
||||
assertEquals(layer.getLocationTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLocationAsConstant() {
|
||||
Timber.i("location");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLocation().getValue());
|
||||
|
||||
// Set and Get
|
||||
Double[] propertyValue = new Double[] {0.0, 0.0, 0.0};
|
||||
layer.setProperties(location(propertyValue));
|
||||
assertEquals(layer.getLocation().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusTransition() {
|
||||
Timber.i("accuracy-radiusTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setAccuracyRadiusTransition(options);
|
||||
assertEquals(layer.getAccuracyRadiusTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusAsConstant() {
|
||||
Timber.i("accuracy-radius");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getAccuracyRadius().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(accuracyRadius(propertyValue));
|
||||
assertEquals(layer.getAccuracyRadius().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testTopImageSizeTransition() {
|
||||
Timber.i("top-image-sizeTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setTopImageSizeTransition(options);
|
||||
assertEquals(layer.getTopImageSizeTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testTopImageSizeAsConstant() {
|
||||
Timber.i("top-image-size");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getTopImageSize().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(topImageSize(propertyValue));
|
||||
assertEquals(layer.getTopImageSize().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBearingImageSizeTransition() {
|
||||
Timber.i("bearing-image-sizeTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setBearingImageSizeTransition(options);
|
||||
assertEquals(layer.getBearingImageSizeTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBearingImageSizeAsConstant() {
|
||||
Timber.i("bearing-image-size");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBearingImageSize().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(bearingImageSize(propertyValue));
|
||||
assertEquals(layer.getBearingImageSize().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testShadowImageSizeTransition() {
|
||||
Timber.i("shadow-image-sizeTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setShadowImageSizeTransition(options);
|
||||
assertEquals(layer.getShadowImageSizeTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testShadowImageSizeAsConstant() {
|
||||
Timber.i("shadow-image-size");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getShadowImageSize().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(shadowImageSize(propertyValue));
|
||||
assertEquals(layer.getShadowImageSize().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusColorTransition() {
|
||||
Timber.i("accuracy-radius-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setAccuracyRadiusColorTransition(options);
|
||||
assertEquals(layer.getAccuracyRadiusColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusColorAsConstant() {
|
||||
Timber.i("accuracy-radius-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getAccuracyRadiusColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(accuracyRadiusColor(propertyValue));
|
||||
assertEquals(layer.getAccuracyRadiusColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusColorAsIntConstant() {
|
||||
Timber.i("accuracy-radius-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(accuracyRadiusColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getAccuracyRadiusColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusBorderColorTransition() {
|
||||
Timber.i("accuracy-radius-border-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setAccuracyRadiusBorderColorTransition(options);
|
||||
assertEquals(layer.getAccuracyRadiusBorderColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusBorderColorAsConstant() {
|
||||
Timber.i("accuracy-radius-border-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getAccuracyRadiusBorderColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(accuracyRadiusBorderColor(propertyValue));
|
||||
assertEquals(layer.getAccuracyRadiusBorderColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAccuracyRadiusBorderColorAsIntConstant() {
|
||||
Timber.i("accuracy-radius-border-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(accuracyRadiusBorderColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getAccuracyRadiusBorderColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,792 @@
|
||||
package org.maplibre.android.location
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.location.Location
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.IdlingRegistry
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import androidx.test.rule.GrantPermissionRule.grant
|
||||
import org.maplibre.android.camera.CameraUpdateFactory
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.location.LocationComponentConstants.*
|
||||
import org.maplibre.android.location.modes.RenderMode
|
||||
import org.maplibre.android.location.utils.*
|
||||
import org.maplibre.android.location.utils.MapLibreTestingUtils.Companion.MAPBOX_HEAVY_STYLE
|
||||
import org.maplibre.android.location.utils.MapLibreTestingUtils.Companion.pushSourceUpdates
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.style.sources.GeoJsonSource
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils
|
||||
import org.maplibre.android.utils.BitmapUtils
|
||||
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
|
||||
import kotlin.math.abs
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class LocationLayerControllerTest : EspressoTest() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val permissionRule: GrantPermissionRule = grant(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
|
||||
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,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.NORMAL
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(style.getSource(LOCATION_SOURCE), notNullValue())
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
//
|
||||
// Location Layers
|
||||
//
|
||||
|
||||
@Test
|
||||
fun renderModeNormal_trackingNormalLayersDoGetAdded() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.NORMAL
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onMapChange_locationComponentPulsingCircleLayerGetsRedrawn() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.locationComponentOptions(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true)
|
||||
.build()
|
||||
)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.NORMAL
|
||||
component.forceLocationUpdate(location)
|
||||
styleChangeIdlingResource.waitForStyle(maplibreMap, Style.getPredefinedStyle("Bright"))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL)))
|
||||
|
||||
// Check that the Source has been re-added to the new map style
|
||||
val source: GeoJsonSource? = maplibreMap.style!!.getSourceAs(LOCATION_SOURCE)
|
||||
assertThat(source, notNullValue())
|
||||
|
||||
// Check that the pulsing circle layer visibilities is set to visible
|
||||
assertThat(maplibreMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun renderModeCompass_bearingLayersDoGetAdded() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.COMPASS
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(true))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulsingCircle_enableLocationComponent_pulsingLayerVisibility() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
component.applyStyle(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true).build()
|
||||
)
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(true))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulsingCircle_disableLocationComponent_pulsingLayerVisibility() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = false
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(PULSING_CIRCLE_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulsingCircle_changeColorCheck() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
component.applyStyle(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true)
|
||||
.pulseColor(Color.RED)
|
||||
.build()
|
||||
)
|
||||
|
||||
component.applyStyle(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true)
|
||||
.pulseColor(Color.BLUE)
|
||||
.build()
|
||||
)
|
||||
|
||||
maplibreMap.style.apply {
|
||||
assertThat(component.locationComponentOptions.pulseColor(), `is`(Color.BLUE))
|
||||
}
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pulsingCircle_changeSpeedCheck() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
component.applyStyle(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true)
|
||||
.pulseSingleDuration(8000f)
|
||||
.build()
|
||||
)
|
||||
|
||||
component.applyStyle(
|
||||
LocationComponentOptions.builder(context)
|
||||
.pulseEnabled(true)
|
||||
.pulseSingleDuration(400f)
|
||||
.build()
|
||||
)
|
||||
|
||||
maplibreMap.style.apply {
|
||||
assertThat(component.locationComponentOptions.pulseSingleDuration(), `is`(400f))
|
||||
}
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun renderModeGps_navigationLayersDoGetAdded() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.GPS
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dontShowPuckWhenRenderModeSetAndComponentDisabled() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
component.isLocationComponentEnabled = false
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
component.renderMode = RenderMode.GPS
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenLocationComponentDisabled_doesSetAllLayersToVisibilityNone() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.NORMAL
|
||||
component.forceLocationUpdate(location)
|
||||
component.isLocationComponentEnabled = false
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
// Check that all layers visibilities are set to none
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onMapChange_locationComponentLayersDoGetRedrawn() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.renderMode = RenderMode.NORMAL
|
||||
component.forceLocationUpdate(location)
|
||||
styleChangeIdlingResource.waitForStyle(maplibreMap, Style.getPredefinedStyle("Bright"))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL)))
|
||||
|
||||
// Check that the Source has been re-added to the new map style
|
||||
val source: GeoJsonSource? = maplibreMap.style!!.getSourceAs(LOCATION_SOURCE)
|
||||
assertThat(source, notNullValue())
|
||||
|
||||
// Check that all layers visibilities are set to visible
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenStyleChanged_continuesUsingStaleIcons() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build())
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
uiController.loopMainThreadForAtLeast(150)
|
||||
|
||||
assertThat(
|
||||
maplibreMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE),
|
||||
`is`(true)
|
||||
)
|
||||
|
||||
maplibreMap.setStyle(Style.Builder().fromUrl(Style.getPredefinedStyle("Bright")))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(
|
||||
maplibreMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE),
|
||||
`is`(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenStyleChanged_isDisabled_hasLayerBelow_staysHidden() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
component.isLocationComponentEnabled = false
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
assertThat(maplibreMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
|
||||
|
||||
val options = component.locationComponentOptions
|
||||
.toBuilder()
|
||||
.layerBelow("road-label")
|
||||
.build()
|
||||
|
||||
component.applyStyle(options)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
assertThat(maplibreMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenStyleChanged_staleStateChanges() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(1).build())
|
||||
styleChangeIdlingResource.waitForStyle(maplibreMap, MAPBOX_HEAVY_STYLE)
|
||||
pushSourceUpdates(styleChangeIdlingResource) {
|
||||
component.forceLocationUpdate(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
|
||||
// Waiting for style to finish loading while pushing updates
|
||||
onView(withId(android.R.id.content)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenStyleChanged_layerVisibilityUpdates() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
styleChangeIdlingResource.waitForStyle(maplibreMap, MAPBOX_HEAVY_STYLE)
|
||||
uiController.loopMainThreadForAtLeast(100)
|
||||
var show = true
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, maplibreMap.style!!)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
pushSourceUpdates(styleChangeIdlingResource) {
|
||||
component.isLocationComponentEnabled = show
|
||||
show = !show
|
||||
}
|
||||
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
|
||||
// Waiting for style to finish loading while pushing updates
|
||||
onView(withId(android.R.id.content)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun accuracy_visibleWithNewLocation() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0))
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
uiController.loopMainThreadForAtLeast(ACCURACY_RADIUS_ANIMATION_DURATION)
|
||||
|
||||
assertEquals(
|
||||
Utils.calculateZoomLevelRadius(maplibreMap, location) /*meters projected to radius on zoom 16*/,
|
||||
maplibreMap.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,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
|
||||
val target = LatLng(location)
|
||||
val zoom = 16.0
|
||||
maplibreMap.easeCamera(CameraUpdateFactory.newLatLngZoom(target, zoom), 300)
|
||||
uiController.loopMainThreadForAtLeast(300)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(
|
||||
Math.abs(zoom - maplibreMap.cameraPosition.zoom) < 0.1 &&
|
||||
Math.abs(target.latitude - maplibreMap.cameraPosition.target!!.latitude) < 0.1 &&
|
||||
Math.abs(target!!.longitude - maplibreMap.cameraPosition.target!!.longitude) < 0.1,
|
||||
`is`(true)
|
||||
)
|
||||
|
||||
val expectedRadius =
|
||||
Utils.calculateZoomLevelRadius(maplibreMap, location) /*meters projected to radius on zoom 16*/
|
||||
assertThat(
|
||||
Math.abs(
|
||||
expectedRadius - maplibreMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(
|
||||
PROPERTY_ACCURACY_RADIUS
|
||||
).toFloat()
|
||||
) < 0.1,
|
||||
`is`(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun accuracy_visibleWhenCameraMoved() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
|
||||
val target = LatLng(location)
|
||||
val zoom = 16.0
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(target, zoom))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
assertThat(
|
||||
abs(zoom - maplibreMap.cameraPosition.zoom) < 0.1 &&
|
||||
abs(target.latitude - maplibreMap.cameraPosition.target!!.latitude) < 0.1 &&
|
||||
abs(target!!.longitude - maplibreMap.cameraPosition.target!!.longitude) < 0.1,
|
||||
`is`(true)
|
||||
)
|
||||
|
||||
val expectedRadius =
|
||||
Utils.calculateZoomLevelRadius(maplibreMap, location) /*meters projected to radius on zoom 16*/
|
||||
assertThat(
|
||||
Math.abs(
|
||||
expectedRadius - maplibreMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(
|
||||
PROPERTY_ACCURACY_RADIUS
|
||||
).toFloat()
|
||||
) < 0.1,
|
||||
`is`(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun applyStyle_layerBelow_restoreLayerVisibility() {
|
||||
val componentAction = object : LocationComponentAction.OnPerformLocationComponentAction {
|
||||
override fun onLocationComponentAction(
|
||||
component: LocationComponent,
|
||||
maplibreMap: MapLibreMap,
|
||||
style: Style,
|
||||
uiController: UiController,
|
||||
context: Context
|
||||
) {
|
||||
component.activateLocationComponent(
|
||||
LocationComponentActivationOptions
|
||||
.builder(context, style)
|
||||
.useDefaultLocationEngine(false)
|
||||
.build()
|
||||
)
|
||||
component.isLocationComponentEnabled = true
|
||||
component.forceLocationUpdate(location)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
|
||||
component.applyStyle(LocationComponentOptions.builder(context).layerBelow("road-label").build())
|
||||
|
||||
assertThat(maplibreMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(SHADOW_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
|
||||
assertThat(maplibreMap.isLayerVisible(BEARING_LAYER), `is`(false))
|
||||
}
|
||||
}
|
||||
executeComponentTest(componentAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun test_15026_missingShadowGradientRadius() {
|
||||
// test for https://github.com/mapbox/mapbox-gl-native/issues/15026
|
||||
val shadowDrawable = BitmapUtils.getDrawableFromRes(context, R.drawable.mapbox_user_icon_shadow_0px_test)
|
||||
Utils.generateShadow(shadowDrawable, 0f)
|
||||
}
|
||||
|
||||
@After
|
||||
override fun afterTest() {
|
||||
super.afterTest()
|
||||
IdlingRegistry.getInstance().unregister(styleChangeIdlingResource)
|
||||
}
|
||||
|
||||
private fun executeComponentTest(listener: LocationComponentAction.OnPerformLocationComponentAction) {
|
||||
onView(withId(android.R.id.content)).perform(LocationComponentAction(maplibreMap, listener))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.maplibre.android.location.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import org.maplibre.android.location.LocationComponent
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.hamcrest.Matcher
|
||||
|
||||
class LocationComponentAction(
|
||||
private val maplibreMap: MapLibreMap,
|
||||
private val onPerformLocationComponentAction: OnPerformLocationComponentAction
|
||||
) : ViewAction {
|
||||
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return isDisplayed()
|
||||
}
|
||||
|
||||
override fun getDescription(): String {
|
||||
return javaClass.simpleName
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
onPerformLocationComponentAction.onLocationComponentAction(
|
||||
maplibreMap.locationComponent,
|
||||
maplibreMap,
|
||||
maplibreMap.style!!,
|
||||
uiController,
|
||||
view.context
|
||||
)
|
||||
}
|
||||
|
||||
interface OnPerformLocationComponentAction {
|
||||
fun onLocationComponentAction(component: LocationComponent, maplibreMap: MapLibreMap, style: Style, uiController: UiController, context: Context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.maplibre.android.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 com.mapbox.geojson.Feature
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.style.layers.Property
|
||||
import org.maplibre.android.style.sources.GeoJsonSource
|
||||
|
||||
fun MapLibreMap.querySourceFeatures(sourceId: String): List<Feature> {
|
||||
return this.style!!.getSourceAs<GeoJsonSource>(sourceId)?.querySourceFeatures(null) ?: emptyList()
|
||||
}
|
||||
|
||||
fun MapLibreMap.queryRenderedFeatures(location: Location, layerId: String): List<Feature> {
|
||||
val latLng = LatLng(location.latitude, location.longitude)
|
||||
val point = this.projection.toScreenLocation(latLng)
|
||||
return this.queryRenderedFeatures(point, layerId)
|
||||
}
|
||||
|
||||
fun MapLibreMap.isLayerVisible(layerId: String): Boolean {
|
||||
return this.style!!.getLayer(layerId)?.visibility?.value?.equals(Property.VISIBLE)!!
|
||||
}
|
||||
|
||||
class MapLibreTestingUtils {
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 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 MapLibreMap.addImageFromDrawable(string: String, drawable: Drawable) {
|
||||
val bitmapFromDrawable = getBitmapFromDrawable(drawable)
|
||||
this.style!!.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
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.maplibre.android.location.utils
|
||||
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
|
||||
/**
|
||||
* 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(maplibreMap: MapLibreMap, styleUrl: String) {
|
||||
isIdle = false
|
||||
maplibreMap.setStyle(Style.Builder().fromUri(styleUrl)) {
|
||||
setIdle()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.style.layers.Layer
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
abstract class BaseLayerTest : AppCenter() {
|
||||
private lateinit var nativeMapView: NativeMap
|
||||
|
||||
companion object {
|
||||
const val WIDTH = 500
|
||||
const val HEIGHT = WIDTH
|
||||
}
|
||||
|
||||
fun before() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
nativeMapView = NativeMapView(context, false, null, null, NativeMapViewTest.DummyRenderer(context))
|
||||
nativeMapView.resizeView(WIDTH, HEIGHT)
|
||||
}
|
||||
|
||||
fun setupLayer(layer: Layer) {
|
||||
nativeMapView.addLayer(layer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.MapLibre
|
||||
import org.maplibre.android.WellKnownTileServer
|
||||
import org.maplibre.android.storage.FileSource
|
||||
import org.maplibre.android.util.TileServerOptions
|
||||
import org.junit.*
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class BootstrapTest : AppCenter() {
|
||||
|
||||
var apiKeyBackup: String? = null
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
fun before() {
|
||||
apiKeyBackup = MapLibre.getApiKey()
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
fun after() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
MapLibre.getInstance(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun defaultBootstrap() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
MapLibre.getInstance(context)
|
||||
|
||||
val tileServerOptions = TileServerOptions.get(WellKnownTileServer.MapLibre)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().count() == tileServerOptions.defaultStyles.count()
|
||||
)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().first().url == tileServerOptions.defaultStyles.first().url
|
||||
)
|
||||
|
||||
val fileSource = FileSource.getInstance(context)
|
||||
Assert.assertEquals(fileSource.apiBaseUrl, tileServerOptions.baseURL)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun maptilerBootstrap() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
val key = "abcdef"
|
||||
MapLibre.getInstance(context, key, WellKnownTileServer.MapTiler)
|
||||
|
||||
val tileServerOptions = TileServerOptions.get(WellKnownTileServer.MapTiler)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().count() == tileServerOptions.defaultStyles.count()
|
||||
)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().first().url == tileServerOptions.defaultStyles.first().url
|
||||
)
|
||||
|
||||
val fileSource = FileSource.getInstance(context)
|
||||
Assert.assertEquals(fileSource.apiBaseUrl, tileServerOptions.baseURL)
|
||||
Assert.assertEquals(fileSource.apiKey, key)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun duplicateBootstrap() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
|
||||
val key = "pk.abcdef"
|
||||
|
||||
MapLibre.getInstance(context, key, WellKnownTileServer.MapTiler)
|
||||
MapLibre.getInstance(context)
|
||||
MapLibre.getInstance(context, key, WellKnownTileServer.Mapbox)
|
||||
|
||||
val tileServerOptions = TileServerOptions.get(WellKnownTileServer.Mapbox)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().count() == tileServerOptions.defaultStyles.count()
|
||||
)
|
||||
Assert.assertTrue(
|
||||
Style.getPredefinedStyles().first().url == tileServerOptions.defaultStyles.first().url
|
||||
)
|
||||
|
||||
val fileSource = FileSource.getInstance(context)
|
||||
Assert.assertEquals(fileSource.apiBaseUrl, tileServerOptions.baseURL)
|
||||
Assert.assertEquals(fileSource.apiKey, key)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,517 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.os.SystemClock
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.test.espresso.Espresso
|
||||
import androidx.test.espresso.InjectEventSecurityException
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import org.hamcrest.Matcher
|
||||
|
||||
object GesturesUiTestUtils {
|
||||
|
||||
private const val DEFAULT_GESTURE_DURATION = 500L
|
||||
|
||||
fun pinch(
|
||||
startSpan: Float,
|
||||
endSpan: Float,
|
||||
center: PointF? = null,
|
||||
duration: Long = DEFAULT_GESTURE_DURATION
|
||||
): ViewAction {
|
||||
return object : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return ViewMatchers.isEnabled()
|
||||
}
|
||||
|
||||
override fun getDescription(): String = "Pinch $startSpan -> $endSpan"
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
var middlePosition = center
|
||||
if (middlePosition == null) {
|
||||
middlePosition = getCenterPointF(view)
|
||||
}
|
||||
|
||||
val startPoint1 = PointF(middlePosition.x - startSpan / 2f, middlePosition.y)
|
||||
val startPoint2 = PointF(middlePosition.x + startSpan / 2f, middlePosition.y)
|
||||
val endPoint1 = PointF(middlePosition.x - endSpan / 2f, middlePosition.y)
|
||||
val endPoint2 = PointF(middlePosition.x + endSpan / 2f, middlePosition.y)
|
||||
|
||||
performPinch(uiController, startPoint1, startPoint2, endPoint1, endPoint2, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun quickScale(
|
||||
deltaY: Float,
|
||||
startPoint: PointF? = null,
|
||||
withVelocity: Boolean = true,
|
||||
duration: Long = DEFAULT_GESTURE_DURATION,
|
||||
interrupt: Boolean = false
|
||||
): ViewAction {
|
||||
return object : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
|
||||
|
||||
override fun getDescription(): String = "quick scale ${deltaY}Y"
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
var middlePosition = startPoint
|
||||
if (middlePosition == null) {
|
||||
middlePosition = getCenterPointF(view)
|
||||
}
|
||||
|
||||
val endPoint = PointF(middlePosition.x, middlePosition.y + deltaY)
|
||||
|
||||
performQuickScale(uiController, middlePosition, endPoint, withVelocity, duration, interrupt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun move(
|
||||
deltaX: Float,
|
||||
deltaY: Float,
|
||||
startPoint: PointF? = null,
|
||||
withVelocity: Boolean = true,
|
||||
duration: Long = DEFAULT_GESTURE_DURATION
|
||||
): ViewAction {
|
||||
return object : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
|
||||
|
||||
override fun getDescription(): String = "move ${deltaX}X, ${deltaY}Y"
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
var middlePosition = startPoint
|
||||
if (middlePosition == null) {
|
||||
middlePosition = getCenterPointF(view)
|
||||
}
|
||||
|
||||
val endPoint = PointF(middlePosition.x + deltaX, middlePosition.y + deltaY)
|
||||
|
||||
performMove(uiController, middlePosition, endPoint, withVelocity, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCenterPointF(view: View): PointF {
|
||||
val locationOnScreen = IntArray(2)
|
||||
view.getLocationOnScreen(locationOnScreen)
|
||||
val viewHeight = view.height * view.scaleY
|
||||
val viewWidth = view.width * view.scaleX
|
||||
return PointF(
|
||||
(locationOnScreen[0] + viewWidth / 2).toInt().toFloat(),
|
||||
(locationOnScreen[1] + viewHeight / 2).toInt().toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/46443628/9126211
|
||||
private fun performPinch(
|
||||
uiController: UiController,
|
||||
startPoint1: PointF,
|
||||
startPoint2: PointF,
|
||||
endPoint1: PointF,
|
||||
endPoint2: PointF,
|
||||
duration: Long
|
||||
) {
|
||||
val eventMinInterval: Long = 10
|
||||
val startTime = SystemClock.uptimeMillis()
|
||||
var eventTime = startTime
|
||||
var event: MotionEvent
|
||||
var eventX1: Float = startPoint1.x
|
||||
var eventY1: Float = startPoint1.y
|
||||
var eventX2: Float = startPoint2.x
|
||||
var eventY2: Float = startPoint2.y
|
||||
|
||||
// Specify the property for the two touch points
|
||||
val properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
|
||||
val pp1 = MotionEvent.PointerProperties()
|
||||
pp1.id = 0
|
||||
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
|
||||
val pp2 = MotionEvent.PointerProperties()
|
||||
pp2.id = 1
|
||||
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
|
||||
|
||||
properties[0] = pp1
|
||||
properties[1] = pp2
|
||||
|
||||
// Specify the coordinations of the two touch points
|
||||
// NOTE: you MUST set the pressure and size value, or it doesn't work
|
||||
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
|
||||
val pc1 = MotionEvent.PointerCoords()
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
pc1.pressure = 1f
|
||||
pc1.size = 1f
|
||||
val pc2 = MotionEvent.PointerCoords()
|
||||
pc2.x = eventX2
|
||||
pc2.y = eventY2
|
||||
pc2.pressure = 1f
|
||||
pc2.size = 1f
|
||||
pointerCoords[0] = pc1
|
||||
pointerCoords[1] = pc2
|
||||
|
||||
/*
|
||||
* Events sequence of zoom gesture:
|
||||
*
|
||||
* 1. Send ACTION_DOWN event of one start point
|
||||
* 2. Send ACTION_POINTER_DOWN of two start points
|
||||
* 3. Send ACTION_MOVE of two middle points
|
||||
* 4. Repeat step 3 with updated middle points (x,y), until reach the end points
|
||||
* 5. Send ACTION_POINTER_UP of two end points
|
||||
* 6. Send ACTION_UP of one end point
|
||||
*/
|
||||
|
||||
try {
|
||||
// Step 1
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_DOWN, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 2
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
|
||||
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 3, 4
|
||||
val moveEventNumber = duration / eventMinInterval
|
||||
|
||||
val stepX1: Float
|
||||
val stepY1: Float
|
||||
val stepX2: Float
|
||||
val stepY2: Float
|
||||
|
||||
stepX1 = (endPoint1.x - startPoint1.x) / moveEventNumber
|
||||
stepY1 = (endPoint1.y - startPoint1.y) / moveEventNumber
|
||||
stepX2 = (endPoint2.x - startPoint2.x) / moveEventNumber
|
||||
stepY2 = (endPoint2.y - startPoint2.y) / moveEventNumber
|
||||
|
||||
for (i in 0 until moveEventNumber) {
|
||||
// Update the move events
|
||||
eventTime += eventMinInterval
|
||||
eventX1 += stepX1
|
||||
eventY1 += stepY1
|
||||
eventX2 += stepX2
|
||||
eventY2 += stepY2
|
||||
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
pc2.x = eventX2
|
||||
pc2.y = eventY2
|
||||
|
||||
pointerCoords[0] = pc1
|
||||
pointerCoords[1] = pc2
|
||||
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_MOVE, 2, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
}
|
||||
|
||||
// Step 5
|
||||
pc1.x = endPoint1.x
|
||||
pc1.y = endPoint1.y
|
||||
pc2.x = endPoint2.x
|
||||
pc2.y = endPoint2.y
|
||||
pointerCoords[0] = pc1
|
||||
pointerCoords[1] = pc2
|
||||
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_POINTER_UP + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 6
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_UP, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
} catch (ex: InjectEventSecurityException) {
|
||||
throw RuntimeException("Could not perform pinch", ex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun performQuickScale(
|
||||
uiController: UiController,
|
||||
startPoint: PointF,
|
||||
endPoint: PointF,
|
||||
withVelocity: Boolean,
|
||||
duration: Long,
|
||||
interrupt: Boolean
|
||||
) {
|
||||
val eventMinInterval: Long = 10
|
||||
|
||||
val tapDownMinInterval: Long = 40 // ViewConfiguration#DOUBLE_TAP_MIN_TIME = 40
|
||||
val startTime = SystemClock.uptimeMillis()
|
||||
var eventTime = startTime
|
||||
var event: MotionEvent
|
||||
var eventX1: Float = startPoint.x
|
||||
var eventY1: Float = startPoint.y
|
||||
|
||||
var properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
|
||||
val pp1 = MotionEvent.PointerProperties()
|
||||
pp1.id = 0
|
||||
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
|
||||
properties[0] = pp1
|
||||
|
||||
var pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
|
||||
val pc1 = MotionEvent.PointerCoords()
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
pc1.pressure = 1f
|
||||
pc1.size = 1f
|
||||
pointerCoords[0] = pc1
|
||||
|
||||
/*
|
||||
* Events sequence of quick scale gesture:
|
||||
*
|
||||
* 1. Send ACTION_DOWN
|
||||
* 2. Send ACTION_UP
|
||||
* 3. Send ACTION_DOWN
|
||||
* 4. Send ACTION_MOVE with updated middle points (x,y), until reach the end points
|
||||
* 5. Send ACTION_UP of one end point
|
||||
*/
|
||||
try {
|
||||
// Step 1
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_DOWN, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 2
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_UP, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 3
|
||||
eventTime += tapDownMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_DOWN, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 4
|
||||
val moveEventNumber = duration / eventMinInterval
|
||||
|
||||
val stepX1: Float
|
||||
val stepY1: Float
|
||||
|
||||
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
|
||||
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
|
||||
|
||||
var interrupted = false
|
||||
|
||||
for (i in 0 until moveEventNumber) {
|
||||
// Update the move events
|
||||
eventTime += eventMinInterval
|
||||
eventX1 += stepX1
|
||||
eventY1 += stepY1
|
||||
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
|
||||
pointerCoords[0] = pc1
|
||||
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_MOVE, if (interrupted) 2 else 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
if (interrupt && i == moveEventNumber / 2) {
|
||||
// Specify the property for the two touch points
|
||||
properties = arrayOfNulls<MotionEvent.PointerProperties>(2)
|
||||
val pp2 = MotionEvent.PointerProperties()
|
||||
pp2.id = 1
|
||||
pp2.toolType = MotionEvent.TOOL_TYPE_FINGER
|
||||
|
||||
properties[0] = pp1
|
||||
properties[1] = pp2
|
||||
|
||||
// Specify the coordinations of the two touch points
|
||||
// NOTE: you MUST set the pressure and size value, or it doesn't work
|
||||
pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(2)
|
||||
val pc2 = MotionEvent.PointerCoords()
|
||||
pc2.x = startPoint.x
|
||||
pc2.y = startPoint.y
|
||||
pc2.pressure = 1f
|
||||
pc2.size = 1f
|
||||
pointerCoords[0] = pc1
|
||||
pointerCoords[1] = pc2
|
||||
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_POINTER_DOWN + (pp2.id shl MotionEvent.ACTION_POINTER_INDEX_SHIFT), 2,
|
||||
properties, pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
interrupted = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!withVelocity) {
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_MOVE, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
}
|
||||
|
||||
// Step 5
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_UP, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
} catch (ex: InjectEventSecurityException) {
|
||||
throw RuntimeException("Could not perform quick scale", ex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun performMove(
|
||||
uiController: UiController,
|
||||
startPoint: PointF,
|
||||
endPoint: PointF,
|
||||
withVelocity: Boolean,
|
||||
duration: Long
|
||||
) {
|
||||
val eventMinInterval: Long = 10
|
||||
val startTime = SystemClock.uptimeMillis()
|
||||
var eventTime = startTime
|
||||
var event: MotionEvent
|
||||
var eventX1: Float = startPoint.x
|
||||
var eventY1: Float = startPoint.y
|
||||
|
||||
val properties = arrayOfNulls<MotionEvent.PointerProperties>(1)
|
||||
val pp1 = MotionEvent.PointerProperties()
|
||||
pp1.id = 0
|
||||
pp1.toolType = MotionEvent.TOOL_TYPE_FINGER
|
||||
properties[0] = pp1
|
||||
|
||||
val pointerCoords = arrayOfNulls<MotionEvent.PointerCoords>(1)
|
||||
val pc1 = MotionEvent.PointerCoords()
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
pc1.pressure = 1f
|
||||
pc1.size = 1f
|
||||
pointerCoords[0] = pc1
|
||||
|
||||
/*
|
||||
* Events sequence of move gesture:
|
||||
*
|
||||
* 1. Send ACTION_DOWN
|
||||
* 2. Send ACTION_MOVE with updated middle points (x,y), until reach the end points
|
||||
* 3. Send ACTION_UP
|
||||
*/
|
||||
try {
|
||||
// Step 1
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_DOWN, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
|
||||
// Step 2
|
||||
val moveEventNumber = duration / eventMinInterval
|
||||
|
||||
val stepX1: Float
|
||||
val stepY1: Float
|
||||
|
||||
stepX1 = (endPoint.x - startPoint.x) / moveEventNumber
|
||||
stepY1 = (endPoint.y - startPoint.y) / moveEventNumber
|
||||
|
||||
for (i in 0 until moveEventNumber) {
|
||||
// Update the move events
|
||||
eventTime += eventMinInterval
|
||||
eventX1 += stepX1
|
||||
eventY1 += stepY1
|
||||
|
||||
pc1.x = eventX1
|
||||
pc1.y = eventY1
|
||||
|
||||
pointerCoords[0] = pc1
|
||||
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_MOVE, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
}
|
||||
|
||||
if (!withVelocity) {
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_MOVE, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
}
|
||||
|
||||
// Step 3
|
||||
eventTime += eventMinInterval
|
||||
event = MotionEvent.obtain(
|
||||
startTime, eventTime,
|
||||
MotionEvent.ACTION_UP, 1, properties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, 0, 0
|
||||
)
|
||||
injectMotionEventToUiController(uiController, event)
|
||||
} catch (ex: InjectEventSecurityException) {
|
||||
throw RuntimeException("Could not perform quick scale", ex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely call uiController.injectMotionEvent(event): Detect any error and "convert" it to an
|
||||
* IllegalStateException
|
||||
*/
|
||||
@Throws(InjectEventSecurityException::class)
|
||||
private fun injectMotionEventToUiController(uiController: UiController, event: MotionEvent) {
|
||||
val injectEventSucceeded = uiController.injectMotionEvent(event)
|
||||
if (!injectEventSucceeded) {
|
||||
throw IllegalStateException("Error performing event $event")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.loopFor(millis: Long) {
|
||||
Espresso.onView(ViewMatchers.withId(this)).perform(object : ViewAction {
|
||||
override fun getDescription(): String = "waiting for $millis"
|
||||
|
||||
override fun getConstraints(): Matcher<View> = ViewMatchers.isEnabled()
|
||||
|
||||
override fun perform(uiController: UiController?, view: View?) {
|
||||
uiController?.loopMainThreadForAtLeast(millis)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import org.maplibre.android.annotations.Icon
|
||||
import timber.log.Timber
|
||||
|
||||
class IconManagerResolver(maplibreMap: MapLibreMap?) {
|
||||
private var iconManager: IconManager? = null
|
||||
|
||||
init {
|
||||
try {
|
||||
val annotationManagerField = MapLibreMap::class.java.getDeclaredField("annotationManager")
|
||||
annotationManagerField.isAccessible = true
|
||||
val annotationManager = annotationManagerField[maplibreMap] as AnnotationManager
|
||||
val iconManagerField = AnnotationManager::class.java.getDeclaredField("iconManager")
|
||||
iconManagerField.isAccessible = true
|
||||
iconManager = iconManagerField[annotationManager] as IconManager
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "Could not create IconManagerResolver, unable to reflect.")
|
||||
}
|
||||
}
|
||||
|
||||
val iconMap: Map<Icon, Int>
|
||||
get() {
|
||||
try {
|
||||
val field = IconManager::class.java.getDeclaredField("iconMap")
|
||||
field.isAccessible = true
|
||||
return field[iconManager] as Map<Icon, Int>
|
||||
} catch (exception: NoSuchFieldException) {
|
||||
Timber.e(exception, "Could not getIconMap, unable to reflect.")
|
||||
} catch (exception: IllegalAccessException) {
|
||||
Timber.e(exception, "Could not getIconMap, unable to reflect.")
|
||||
}
|
||||
return HashMap()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import org.maplibre.android.camera.CameraPosition
|
||||
import org.maplibre.android.camera.CameraUpdateFactory
|
||||
import org.maplibre.android.constants.MapLibreConstants
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.GesturesUiTestUtils.move
|
||||
import org.maplibre.android.maps.GesturesUiTestUtils.quickScale
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.BaseTest
|
||||
import org.maplibre.android.testapp.activity.maplayout.SimpleMapActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class MapGestureDetectorTest : BaseTest() {
|
||||
override fun getActivityClass() = SimpleMapActivity::class.java
|
||||
|
||||
private var maxWidth: Int = 0
|
||||
private var maxHeight: Int = 0
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
maxWidth = mapView.width
|
||||
maxHeight = mapView.height
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sanity_quickZoom() {
|
||||
validateTestSetup()
|
||||
var initialZoom: Double? = null
|
||||
rule.runOnUiThread {
|
||||
initialZoom = maplibreMap.cameraPosition.zoom
|
||||
}
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, withVelocity = false))
|
||||
rule.runOnUiThread {
|
||||
Assert.assertTrue(maplibreMap.cameraPosition.zoom > initialZoom!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun quickZoomDisabled_phantomQuickZoom_moveStillEnabled_15091() {
|
||||
// regression test for https://github.com/mapbox/mapbox-gl-native/issues/15091
|
||||
validateTestSetup()
|
||||
var initialCameraPosition: CameraPosition? = null
|
||||
rule.runOnUiThread {
|
||||
// zoom in so we can move vertically
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
|
||||
initialCameraPosition = maplibreMap.cameraPosition
|
||||
maplibreMap.uiSettings.isQuickZoomGesturesEnabled = false
|
||||
}
|
||||
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
|
||||
rule.runOnUiThread {
|
||||
// camera did not move
|
||||
Assert.assertEquals(initialCameraPosition!!, maplibreMap.cameraPosition)
|
||||
}
|
||||
|
||||
// move to expected target
|
||||
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
|
||||
rule.runOnUiThread {
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.latitude, maplibreMap.cameraPosition.target!!.latitude, 1.0)
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.longitude, maplibreMap.cameraPosition.target!!.longitude, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun quickZoom_doNotMove_14227() {
|
||||
// test for https://github.com/mapbox/mapbox-gl-native/issues/14227
|
||||
validateTestSetup()
|
||||
var initialTarget: LatLng? = null
|
||||
rule.runOnUiThread {
|
||||
initialTarget = maplibreMap.cameraPosition.target!!
|
||||
}
|
||||
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f))
|
||||
rule.runOnUiThread {
|
||||
// camera did not move
|
||||
Assert.assertEquals(initialTarget!!.latitude, maplibreMap.cameraPosition.target!!.latitude, 1.0)
|
||||
Assert.assertEquals(initialTarget!!.longitude, maplibreMap.cameraPosition.target!!.longitude, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun quickZoom_interrupted_moveStillEnabled_14598() {
|
||||
// test for https://github.com/mapbox/mapbox-gl-native/issues/14598
|
||||
validateTestSetup()
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maxHeight / 2f, interrupt = true))
|
||||
|
||||
var initialCameraPosition: CameraPosition? = null
|
||||
rule.runOnUiThread {
|
||||
// zoom in so we can move vertically
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
|
||||
initialCameraPosition = maplibreMap.cameraPosition
|
||||
maplibreMap.uiSettings.isQuickZoomGesturesEnabled = false
|
||||
}
|
||||
|
||||
// move to expected target
|
||||
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
|
||||
rule.runOnUiThread {
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.latitude, maplibreMap.cameraPosition.target!!.latitude, 1.0)
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.longitude, maplibreMap.cameraPosition.target!!.longitude, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun quickZoom_ignoreDoubleTap() {
|
||||
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
|
||||
validateTestSetup()
|
||||
var initialZoom: Double? = null
|
||||
rule.runOnUiThread {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.zoomTo(2.0))
|
||||
initialZoom = maplibreMap.cameraPosition.zoom
|
||||
}
|
||||
onView(withId(R.id.mapView)).perform(quickScale(-(maplibreMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2), withVelocity = false, duration = 1000L))
|
||||
R.id.mapView.loopFor(MapLibreConstants.ANIMATION_DURATION.toLong())
|
||||
rule.runOnUiThread {
|
||||
Assert.assertTrue(maplibreMap.cameraPosition.zoom < initialZoom!!)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doubleTap_minimalMovement() {
|
||||
validateTestSetup()
|
||||
var initialZoom: Double? = null
|
||||
rule.runOnUiThread {
|
||||
initialZoom = maplibreMap.cameraPosition.zoom
|
||||
}
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maplibreMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L))
|
||||
R.id.mapView.loopFor(MapLibreConstants.ANIMATION_DURATION.toLong())
|
||||
rule.runOnUiThread {
|
||||
Assert.assertEquals(initialZoom!! + 1, maplibreMap.cameraPosition.zoom, 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doubleTap_overMaxThreshold_ignore_14013() {
|
||||
// test for https://github.com/mapbox/mapbox-gl-native/issues/14013
|
||||
validateTestSetup()
|
||||
var initialZoom: Double? = null
|
||||
rule.runOnUiThread {
|
||||
initialZoom = maplibreMap.cameraPosition.zoom
|
||||
maplibreMap.uiSettings.isQuickZoomGesturesEnabled = false
|
||||
}
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maplibreMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold * 2, withVelocity = false, duration = 50L))
|
||||
R.id.mapView.loopFor(MapLibreConstants.ANIMATION_DURATION.toLong())
|
||||
rule.runOnUiThread {
|
||||
Assert.assertEquals(initialZoom!!, maplibreMap.cameraPosition.zoom, 0.01)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doubleTap_interrupted_moveStillEnabled() {
|
||||
validateTestSetup()
|
||||
|
||||
rule.runOnUiThread {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
|
||||
}
|
||||
|
||||
onView(withId(R.id.mapView)).perform(quickScale(maplibreMap.gesturesManager.standardScaleGestureDetector.spanSinceStartThreshold / 2, withVelocity = false, duration = 50L, interrupt = true))
|
||||
|
||||
var initialCameraPosition: CameraPosition? = null
|
||||
rule.runOnUiThread {
|
||||
// zoom in so we can move vertically
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.zoomTo(4.0))
|
||||
initialCameraPosition = maplibreMap.cameraPosition
|
||||
maplibreMap.uiSettings.isQuickZoomGesturesEnabled = false
|
||||
}
|
||||
|
||||
// move to expected target
|
||||
onView(withId(R.id.mapView)).perform(move(-maxWidth / 2f, -maxHeight / 2f, withVelocity = false))
|
||||
rule.runOnUiThread {
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.latitude, maplibreMap.cameraPosition.target!!.latitude, 1.0)
|
||||
Assert.assertNotEquals(initialCameraPosition!!.target!!.longitude, maplibreMap.cameraPosition.target!!.longitude, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun quickZoom_roundTripping() {
|
||||
validateTestSetup()
|
||||
rule.runOnUiThread {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(51.0, 16.0), 3.0))
|
||||
}
|
||||
onView(withId(R.id.mapView)).perform(quickScale(300f, withVelocity = false, duration = 750L))
|
||||
onView(withId(R.id.mapView)).perform(quickScale(-300f, withVelocity = false, duration = 750L))
|
||||
|
||||
rule.runOnUiThread {
|
||||
Assert.assertEquals(3.0, maplibreMap.cameraPosition.zoom, 0.001)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import junit.framework.TestCase
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.maplibre.android.annotations.BaseMarkerOptions
|
||||
import org.maplibre.android.annotations.Marker
|
||||
import org.maplibre.android.annotations.MarkerOptions
|
||||
import org.maplibre.android.annotations.PolygonOptions
|
||||
import org.maplibre.android.annotations.PolylineOptions
|
||||
import org.maplibre.android.exceptions.InvalidMarkerPositionException
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.MapLibreMap.InfoWindowAdapter
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
|
||||
// J2K: IDE suggest "Add 'fun' modifier
|
||||
|
||||
/**
|
||||
* This test is responsible for testing the public API.
|
||||
*
|
||||
*
|
||||
* Methods executed on MapboxMap are called from a ViewAction to ensure correct synchronisation
|
||||
* with the application UI-thread.
|
||||
*
|
||||
*/
|
||||
@Deprecated("remove this file when removing deprecated annotations")
|
||||
class MapLibreMapTest : EspressoTest() {
|
||||
//
|
||||
// InfoWindow
|
||||
//
|
||||
@Test
|
||||
fun testConcurrentInfoWindowEnabled() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
maplibreMap.isAllowConcurrentMultipleOpenInfoWindows = true
|
||||
assertTrue("ConcurrentWindows should be true", maplibreMap.isAllowConcurrentMultipleOpenInfoWindows)
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConcurrentInfoWindowDisabled() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
maplibreMap.isAllowConcurrentMultipleOpenInfoWindows = false
|
||||
TestCase.assertFalse("ConcurrentWindows should be false", maplibreMap.isAllowConcurrentMultipleOpenInfoWindows)
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInfoWindowAdapter() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val infoWindowAdapter = InfoWindowAdapter { marker: Marker? -> null }
|
||||
maplibreMap.infoWindowAdapter = infoWindowAdapter
|
||||
assertEquals("InfoWindowAdpter should be the same", infoWindowAdapter, maplibreMap.infoWindowAdapter)
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// Annotations
|
||||
//
|
||||
@Test
|
||||
fun testAddMarker() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker = maplibreMap.addMarker(markerOptions)
|
||||
assertTrue("Marker should be contained", maplibreMap.markers.contains(marker))
|
||||
})
|
||||
}
|
||||
|
||||
@Test(expected = InvalidMarkerPositionException::class)
|
||||
fun testAddMarkerInvalidPosition() {
|
||||
MarkerOptions().marker
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddMarkers() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: MutableList<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
val markerOptions1 = MarkerOptions().position(LatLng()).title("a")
|
||||
val markerOptions2 = MarkerOptions().position(LatLng()).title("b")
|
||||
markerList.add(markerOptions1)
|
||||
markerList.add(markerOptions2)
|
||||
val markers = maplibreMap.addMarkers(markerList)
|
||||
assertEquals("Markers size should be 2", 2, maplibreMap.markers.size.toLong())
|
||||
assertTrue(maplibreMap.markers.contains(markers[0]))
|
||||
assertTrue(maplibreMap.markers.contains(markers[1]))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddMarkersEmpty() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: List<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
maplibreMap.addMarkers(markerList)
|
||||
assertEquals("Markers size should be 0", 0, maplibreMap.markers.size.toLong())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddMarkersSingleMarker() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: MutableList<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
val markerOptions = MarkerOptions().title("a").position(LatLng())
|
||||
markerList.add(markerOptions)
|
||||
val markers = maplibreMap.addMarkers(markerList)
|
||||
assertEquals("Markers size should be 1", 1, maplibreMap.markers.size.toLong())
|
||||
assertTrue(maplibreMap.markers.contains(markers[0]))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolygon() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polygonOptions = PolygonOptions().add(LatLng())
|
||||
val polygon = maplibreMap.addPolygon(polygonOptions)
|
||||
assertTrue("Polygon should be contained", maplibreMap.polygons.contains(polygon))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddEmptyPolygon() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polygonOptions = PolygonOptions()
|
||||
val polygon = maplibreMap.addPolygon(polygonOptions)
|
||||
assertTrue("Polygon should be ignored", !maplibreMap.polygons.contains(polygon))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolygons() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polygonList: MutableList<PolygonOptions> = ArrayList()
|
||||
val polygonOptions1 = PolygonOptions().fillColor(Color.BLACK).add(LatLng())
|
||||
val polygonOptions2 = PolygonOptions().fillColor(Color.WHITE).add(LatLng())
|
||||
val polygonOptions3 = PolygonOptions()
|
||||
polygonList.add(polygonOptions1)
|
||||
polygonList.add(polygonOptions2)
|
||||
polygonList.add(polygonOptions3)
|
||||
maplibreMap.addPolygons(polygonList)
|
||||
assertEquals("Polygons size should be 2", 2, maplibreMap.polygons.size.toLong())
|
||||
assertTrue(maplibreMap.polygons.contains(polygonOptions1.polygon))
|
||||
assertTrue(maplibreMap.polygons.contains(polygonOptions2.polygon))
|
||||
assertTrue("Polygon should be ignored", !maplibreMap.polygons.contains(polygonOptions3.polygon))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addPolygonsEmpty() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
maplibreMap.addPolygons(ArrayList())
|
||||
assertEquals("Polygons size should be 0", 0, maplibreMap.polygons.size.toLong())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addPolygonsSingle() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polygonList: MutableList<PolygonOptions> = ArrayList()
|
||||
val polygonOptions = PolygonOptions().fillColor(Color.BLACK).add(LatLng())
|
||||
polygonList.add(polygonOptions)
|
||||
maplibreMap.addPolygons(polygonList)
|
||||
assertEquals("Polygons size should be 1", 1, maplibreMap.polygons.size.toLong())
|
||||
assertTrue(maplibreMap.polygons.contains(polygonOptions.polygon))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolyline() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polylineOptions = PolylineOptions().add(LatLng())
|
||||
val polyline = maplibreMap.addPolyline(polylineOptions)
|
||||
assertTrue("Polyline should be contained", maplibreMap.polylines.contains(polyline))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddEmptyPolyline() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polylineOptions = PolylineOptions()
|
||||
val polyline = maplibreMap.addPolyline(polylineOptions)
|
||||
assertTrue("Polyline should be ignored", !maplibreMap.polylines.contains(polyline))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolylines() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polylineList: MutableList<PolylineOptions> = ArrayList()
|
||||
val polygonOptions1 = PolylineOptions().color(Color.BLACK).add(LatLng())
|
||||
val polygonOptions2 = PolylineOptions().color(Color.WHITE).add(LatLng())
|
||||
val polygonOptions3 = PolylineOptions()
|
||||
polylineList.add(polygonOptions1)
|
||||
polylineList.add(polygonOptions2)
|
||||
polylineList.add(polygonOptions3)
|
||||
maplibreMap.addPolylines(polylineList)
|
||||
assertEquals("Polygons size should be 2", 2, maplibreMap.polylines.size.toLong())
|
||||
assertTrue(maplibreMap.polylines.contains(polygonOptions1.polyline))
|
||||
assertTrue(maplibreMap.polylines.contains(polygonOptions2.polyline))
|
||||
assertTrue(
|
||||
"Polyline should be ignored", !maplibreMap.polylines.contains(polygonOptions3.polyline)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolylinesEmpty() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
maplibreMap.addPolylines(ArrayList())
|
||||
assertEquals("Polygons size should be 0", 0, maplibreMap.polylines.size.toLong())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddPolylinesSingle() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polylineList: MutableList<PolylineOptions> = ArrayList()
|
||||
val polygonOptions = PolylineOptions().color(Color.BLACK).add(LatLng())
|
||||
polylineList.add(polygonOptions)
|
||||
maplibreMap.addPolylines(polylineList)
|
||||
assertEquals("Polygons size should be 1", 1, maplibreMap.polylines.size.toLong())
|
||||
assertTrue(maplibreMap.polylines.contains(polygonOptions.polyline))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveMarker() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker = maplibreMap.addMarker(markerOptions)
|
||||
maplibreMap.removeMarker(marker)
|
||||
assertTrue("Markers should be empty", maplibreMap.markers.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemovePolygon() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polygonOptions = PolygonOptions()
|
||||
val polygon = maplibreMap.addPolygon(polygonOptions)
|
||||
maplibreMap.removePolygon(polygon)
|
||||
assertTrue("Polygons should be empty", maplibreMap.polylines.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemovePolyline() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val polylineOptions = PolylineOptions()
|
||||
val polyline = maplibreMap.addPolyline(polylineOptions)
|
||||
maplibreMap.removePolyline(polyline)
|
||||
assertTrue("Polylines should be empty", maplibreMap.polylines.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAnnotation() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker = maplibreMap.addMarker(markerOptions)
|
||||
maplibreMap.removeAnnotation(marker)
|
||||
assertTrue("Annotations should be empty", maplibreMap.annotations.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAnnotationById() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
maplibreMap.addMarker(markerOptions)
|
||||
// id will always be 0 in unit tests
|
||||
maplibreMap.removeAnnotation(0)
|
||||
assertTrue("Annotations should be empty", maplibreMap.annotations.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAnnotations() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: MutableList<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
val markerOptions1 = MarkerOptions().title("a").position(LatLng())
|
||||
val markerOptions2 = MarkerOptions().title("b").position(LatLng())
|
||||
markerList.add(markerOptions1)
|
||||
markerList.add(markerOptions2)
|
||||
maplibreMap.addMarkers(markerList)
|
||||
maplibreMap.removeAnnotations()
|
||||
assertTrue("Annotations should be empty", maplibreMap.annotations.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClear() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: MutableList<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
val markerOptions1 = MarkerOptions().title("a").position(LatLng())
|
||||
val markerOptions2 = MarkerOptions().title("b").position(LatLng())
|
||||
markerList.add(markerOptions1)
|
||||
markerList.add(markerOptions2)
|
||||
maplibreMap.addMarkers(markerList)
|
||||
maplibreMap.clear()
|
||||
assertTrue("Annotations should be empty", maplibreMap.annotations.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveAnnotationsByList() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerList: MutableList<BaseMarkerOptions<*, *>> = ArrayList()
|
||||
val markerOptions1 = MarkerOptions().title("a").position(LatLng())
|
||||
val markerOptions2 = MarkerOptions().title("b").position(LatLng())
|
||||
markerList.add(markerOptions1)
|
||||
markerList.add(markerOptions2)
|
||||
val markers = maplibreMap.addMarkers(markerList)
|
||||
val marker = maplibreMap.addMarker(MarkerOptions().position(LatLng()).title("c"))
|
||||
maplibreMap.removeAnnotations(markers)
|
||||
assertTrue("Annotations should not be empty", maplibreMap.annotations.size == 1)
|
||||
assertTrue("Marker should be contained", maplibreMap.annotations.contains(marker))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetAnnotationById() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val initialMarker = maplibreMap.addMarker(markerOptions)
|
||||
val retrievedMarker = maplibreMap.getAnnotation(0) as Marker?
|
||||
assertEquals("Markers should match", initialMarker, retrievedMarker)
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetAnnotations() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(
|
||||
MapLibreMapAction { uiController: UiController?, view: View? -> TestCase.assertNotNull("Annotations should be non null", maplibreMap.annotations) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetMarkers() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(
|
||||
MapLibreMapAction { uiController: UiController?, view: View? -> TestCase.assertNotNull("Markers should be non null", maplibreMap.markers) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetPolygons() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? -> TestCase.assertNotNull("Polygons should be non null", maplibreMap.polygons) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetPolylines() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? -> TestCase.assertNotNull("Polylines should be non null", maplibreMap.polylines) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSelectedMarkers() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? -> TestCase.assertNotNull("Selected markers should be non null", maplibreMap.selectedMarkers) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSelectMarker() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker = maplibreMap.addMarker(markerOptions)
|
||||
maplibreMap.selectMarker(marker)
|
||||
assertTrue("Marker should be contained", maplibreMap.selectedMarkers.contains(marker))
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeselectMarker() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker = maplibreMap.addMarker(markerOptions)
|
||||
maplibreMap.selectMarker(marker)
|
||||
maplibreMap.deselectMarker(marker)
|
||||
assertTrue("Selected markers should be empty", maplibreMap.selectedMarkers.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeselectMarkers() {
|
||||
validateTestSetup()
|
||||
onView(ViewMatchers.withId(R.id.mapView)).perform(MapLibreMapAction { uiController: UiController?, view: View? ->
|
||||
val markerOptions = MarkerOptions().position(LatLng())
|
||||
val marker1 = maplibreMap.addMarker(markerOptions)
|
||||
val marker2 = maplibreMap.addMarker(markerOptions)
|
||||
maplibreMap.selectMarker(marker1)
|
||||
maplibreMap.selectMarker(marker2)
|
||||
maplibreMap.deselectMarkers()
|
||||
assertTrue("Selected markers should be empty", maplibreMap.selectedMarkers.isEmpty())
|
||||
})
|
||||
}
|
||||
|
||||
inner class MapLibreMapAction internal constructor(private val invokeViewAction: InvokeViewAction) : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return ViewMatchers.isDisplayed()
|
||||
}
|
||||
|
||||
override fun getDescription(): String {
|
||||
return javaClass.simpleName
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
invokeViewAction.onViewAction(uiController, view)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun interface InvokeViewAction {
|
||||
fun onViewAction(uiController: UiController?, view: View?)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.junit.After
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.MapLibre.*
|
||||
import org.maplibre.android.exceptions.MapLibreConfigurationException
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class MapLibreTest : AppCenter() {
|
||||
private var realToken: String? = null
|
||||
@Before
|
||||
fun setup() {
|
||||
realToken = getApiKey()
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testConnected() {
|
||||
assertTrue(isConnected())
|
||||
|
||||
// test manual connectivity
|
||||
setConnected(true)
|
||||
assertTrue(isConnected())
|
||||
setConnected(false)
|
||||
assertFalse(isConnected())
|
||||
|
||||
// reset to Android connectivity
|
||||
setConnected(null)
|
||||
assertTrue(isConnected())
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun setApiKey() {
|
||||
setApiKey(API_KEY)
|
||||
assertSame(API_KEY, getApiKey())
|
||||
setApiKey(API_KEY_2)
|
||||
assertSame(API_KEY_2, getApiKey())
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun setNullApiKey() {
|
||||
assertThrows(MapLibreConfigurationException::class.java) { setApiKey(null) }
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
setApiKey(realToken)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val API_KEY = "pk.0000000001"
|
||||
private const val API_KEY_2 = "pk.0000000002"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.MapLibre
|
||||
import org.maplibre.android.WellKnownTileServer
|
||||
import org.maplibre.android.camera.CameraPosition
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.geometry.LatLngBounds
|
||||
import org.maplibre.android.geometry.ProjectedMeters
|
||||
import org.maplibre.android.maps.renderer.MapRenderer
|
||||
import org.maplibre.android.style.layers.TransitionOptions
|
||||
import org.maplibre.android.testapp.utils.TestConstants
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class NativeMapViewTest : AppCenter() {
|
||||
|
||||
private lateinit var nativeMapView: NativeMap
|
||||
|
||||
companion object {
|
||||
const val DELTA = 0.000001
|
||||
const val DELTA_BIG = 1.0
|
||||
const val BEARING_TEST = 60.0
|
||||
const val PITCH_TEST = 40.0
|
||||
const val ZOOM_TEST = 16.0
|
||||
val PADDING_TEST = doubleArrayOf(80.0, 150.0, 0.0, 0.0)
|
||||
const val WIDTH = 500
|
||||
const val HEIGHT = WIDTH
|
||||
val LATLNG_TEST = LatLng(12.0, 34.0)
|
||||
}
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
fun before() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
val apiKey = MapLibre.getApiKey()
|
||||
MapLibre.getInstance(context, apiKey, WellKnownTileServer.MapTiler)
|
||||
nativeMapView = NativeMapView(context, 2.0f, false, null, null, DummyRenderer(context))
|
||||
nativeMapView.resizeView(WIDTH, HEIGHT)
|
||||
}
|
||||
|
||||
@After
|
||||
@UiThreadTest
|
||||
fun after() {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
val apiKey = MapLibre.getApiKey()
|
||||
MapLibre.getInstance(context)
|
||||
nativeMapView.destroy()
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetStyleUrl() {
|
||||
val expected = Style.getPredefinedStyle("Pastel")
|
||||
nativeMapView.styleUri = expected
|
||||
val actual = nativeMapView.styleUri
|
||||
assertEquals("Style URL should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetStyleJson() {
|
||||
val expected = "{}"
|
||||
nativeMapView.styleJson = expected
|
||||
val actual = nativeMapView.styleJson
|
||||
assertEquals("Style JSON should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testBearing() {
|
||||
val expected = BEARING_TEST
|
||||
nativeMapView.setBearing(expected, 0)
|
||||
val actual = nativeMapView.bearing
|
||||
assertEquals("Bearing should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLng() {
|
||||
val expected = LATLNG_TEST
|
||||
nativeMapView.setLatLng(expected, 0)
|
||||
val actual = nativeMapView.latLng
|
||||
assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA)
|
||||
assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngPadding() {
|
||||
val expected = LATLNG_TEST
|
||||
nativeMapView.contentPadding = PADDING_TEST
|
||||
nativeMapView.setLatLng(expected, 0)
|
||||
val actual = nativeMapView.latLng
|
||||
assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA)
|
||||
assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA)
|
||||
assertArrayEquals(PADDING_TEST, nativeMapView.cameraPosition.padding, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngDefault() {
|
||||
val expected = LatLng()
|
||||
val actual = nativeMapView.latLng
|
||||
assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA)
|
||||
assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testBearingDefault() {
|
||||
val expected = 0.0
|
||||
val actual = nativeMapView.bearing
|
||||
assertEquals("Bearing should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPitch() {
|
||||
val expected = PITCH_TEST
|
||||
nativeMapView.setPitch(expected, 0)
|
||||
val actual = nativeMapView.pitch
|
||||
assertEquals("Pitch should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPitchDefault() {
|
||||
val expected = 0.0
|
||||
val actual = nativeMapView.pitch
|
||||
assertEquals("Pitch should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testZoom() {
|
||||
val expected = ZOOM_TEST
|
||||
nativeMapView.setZoom(expected, PointF(0.0f, 0.0f), 0)
|
||||
val actual = nativeMapView.zoom
|
||||
assertEquals("Zoom should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testZoomDefault() {
|
||||
val expected = 0.0
|
||||
val actual = nativeMapView.zoom
|
||||
assertEquals("Zoom should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testJumpTo() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.bearing(BEARING_TEST)
|
||||
.target(LATLNG_TEST)
|
||||
.tilt(PITCH_TEST)
|
||||
.zoom(ZOOM_TEST)
|
||||
.padding(PADDING_TEST)
|
||||
.build()
|
||||
// verify that the lazily set padding is ignored when a value is provided with the camera
|
||||
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
|
||||
nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST, PADDING_TEST)
|
||||
val actual = nativeMapView.cameraPosition
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, DELTA)
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, DELTA)
|
||||
assertEquals("Pitch should match", expected.tilt, actual.tilt, DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, DELTA)
|
||||
assertArrayEquals(expected.padding, actual.padding, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngForPixel() {
|
||||
val expected = LATLNG_TEST
|
||||
nativeMapView.setLatLng(LATLNG_TEST, 0)
|
||||
val actual = nativeMapView.latLngForPixel(
|
||||
PointF((WIDTH / 2).toFloat(), (HEIGHT / 2).toFloat())
|
||||
)
|
||||
assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA_BIG)
|
||||
assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA_BIG)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPixelForLatLng() {
|
||||
val expected = PointF((WIDTH / 2).toFloat(), (HEIGHT / 2).toFloat())
|
||||
nativeMapView.setLatLng(LATLNG_TEST, 0)
|
||||
val actual = nativeMapView.pixelForLatLng(LATLNG_TEST)
|
||||
assertEquals("X should match", expected.x.toDouble(), actual.x.toDouble(), DELTA_BIG)
|
||||
assertEquals("Y should match", expected.y.toDouble(), actual.y.toDouble(), DELTA_BIG)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPrefetchTilesTrue() {
|
||||
val expected = true
|
||||
nativeMapView.prefetchTiles = true
|
||||
val actual = nativeMapView.prefetchTiles
|
||||
assertEquals("Flag should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPrefetchTilesFalse() {
|
||||
val expected = false
|
||||
nativeMapView.prefetchTiles = false
|
||||
val actual = nativeMapView.prefetchTiles
|
||||
assertEquals("Flag should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPrefetchTilesDefault() {
|
||||
val expected = true
|
||||
val actual = nativeMapView.prefetchTiles
|
||||
assertEquals("Flag should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPrefetchZoomDelta() {
|
||||
val expected = 2
|
||||
nativeMapView.prefetchZoomDelta = 2
|
||||
val actual = nativeMapView.prefetchZoomDelta
|
||||
assertEquals("Prefetch zoom delta should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testPrefetchZoomDeltaDefault() {
|
||||
val expected = 4
|
||||
val actual = nativeMapView.prefetchZoomDelta
|
||||
assertEquals("Prefetch zoom delta should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetContentPadding() {
|
||||
val expected = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
|
||||
nativeMapView.contentPadding = expected
|
||||
val actual = nativeMapView.contentPadding
|
||||
assertEquals("Left should match", expected[0], actual[0], 0.0)
|
||||
assertEquals("Top should match", expected[1], actual[1], 0.0)
|
||||
assertEquals("Right should match", expected[2], actual[2], 0.0)
|
||||
assertEquals("Bottom should match", expected[3], actual[3], 0.0)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetMinZoom() {
|
||||
val expected = 12.0
|
||||
nativeMapView.minZoom = expected
|
||||
val actual = nativeMapView.minZoom
|
||||
assertEquals("Min zoom should match", expected, actual, 0.0)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetMaxZoom() {
|
||||
val expected = 12.0
|
||||
nativeMapView.maxZoom = expected
|
||||
val actual = nativeMapView.maxZoom
|
||||
assertEquals("Max zoom should match", expected, actual, 0.0)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetMinPitch() {
|
||||
val expected = 60.0
|
||||
nativeMapView.minPitch = expected
|
||||
val actual = nativeMapView.minPitch
|
||||
assertEquals("Min Pitch should match", expected, actual, 0.01)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testSetMaxPitch() {
|
||||
val expected = 60.0
|
||||
nativeMapView.maxPitch = expected
|
||||
val actual = nativeMapView.maxPitch
|
||||
assertEquals("Max Pitch should match", expected, actual, 0.01)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testGetProjectedMetersAtLatitude() {
|
||||
val expected = 77973.67021115532
|
||||
val actual = nativeMapView.getMetersPerPixelAtLatitude(5.0)
|
||||
assertEquals("Get projected meters should match", expected, actual, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testLatLngForProjectedMeters() {
|
||||
val expected = LatLng(0.01796630538796444, 0.02694945852363162)
|
||||
val actual = nativeMapView.latLngForProjectedMeters(ProjectedMeters(2000.0, 3000.0))
|
||||
assertEquals("Lat for projected meters", expected.latitude, actual.latitude, DELTA)
|
||||
assertEquals("Lng for projected meters", expected.longitude, actual.longitude, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testFlyTo() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.zoom(12.0)
|
||||
.tilt(30.0)
|
||||
.target(LatLng(12.0, 14.0))
|
||||
.bearing(20.0)
|
||||
.padding(PADDING_TEST)
|
||||
.build()
|
||||
// verify that the lazily set padding is ignored when a value is provided with the camera
|
||||
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
|
||||
nativeMapView.flyTo(expected.target!!, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0)
|
||||
val actual = nativeMapView.cameraPosition
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
|
||||
Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testEaseTo() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.zoom(12.0)
|
||||
.tilt(30.0)
|
||||
.target(LatLng(12.0, 14.0))
|
||||
.bearing(20.0)
|
||||
.padding(PADDING_TEST)
|
||||
.build()
|
||||
// verify that the lazily set padding is ignored when a value is provided with the camera
|
||||
nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
|
||||
nativeMapView.easeTo(expected.target!!, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0, false)
|
||||
val actual = nativeMapView.cameraPosition
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
|
||||
assertArrayEquals(expected.padding, actual.padding, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testResetPosition() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.zoom(0.0)
|
||||
.tilt(0.0)
|
||||
.target(LatLng(0.0, 0.0))
|
||||
.bearing(0.0)
|
||||
.padding(PADDING_TEST)
|
||||
.build()
|
||||
nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0, PADDING_TEST)
|
||||
nativeMapView.resetPosition()
|
||||
val actual = nativeMapView.cameraPosition
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
|
||||
assertArrayEquals(expected.padding, actual.padding, DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testGetCameraForLatLngBounds() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.zoom(3.5258764777024005)
|
||||
.tilt(0.0)
|
||||
.target(LatLng(23.182767623652808, 13.999999999994088))
|
||||
.bearing(0.0)
|
||||
.build()
|
||||
val actual = nativeMapView.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(30.0, 16.0, 16.0, 12.0),
|
||||
intArrayOf(0, 0, 0, 0),
|
||||
0.0,
|
||||
0.0
|
||||
)
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testMoveBy() {
|
||||
val expected = CameraPosition.Builder()
|
||||
.zoom(0.0)
|
||||
.tilt(0.0)
|
||||
.target(LatLng(4.21494310024160, -4.218749958739409))
|
||||
.bearing(0.0)
|
||||
.build()
|
||||
nativeMapView.moveBy(12.0, 12.0, 0)
|
||||
val actual = nativeMapView.cameraPosition
|
||||
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
|
||||
assertEquals("Latitude should match", expected.target!!.latitude, actual.target!!.latitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Longitude should match", expected.target!!.longitude, actual.target!!.longitude, TestConstants.LAT_LNG_DELTA)
|
||||
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
|
||||
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testTransitionOptions() {
|
||||
val transitionOptions = TransitionOptions(500, 500)
|
||||
nativeMapView.transitionOptions = transitionOptions
|
||||
assertTrue(transitionOptions.isEnablePlacementTransitions)
|
||||
assertEquals(transitionOptions, nativeMapView.transitionOptions)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testTransitionOptions_disablePlacementTransitions() {
|
||||
val transitionOptions = TransitionOptions(500, 500, false)
|
||||
nativeMapView.transitionOptions = transitionOptions
|
||||
assertFalse(transitionOptions.isEnablePlacementTransitions)
|
||||
assertEquals(transitionOptions, nativeMapView.transitionOptions)
|
||||
}
|
||||
|
||||
class DummyRenderer(context: Context) : MapRenderer(context, null) {
|
||||
|
||||
override fun requestRender() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override fun queueEvent(runnable: Runnable?) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override fun waitForEmpty(timeoutMillis: Long): Long {
|
||||
// no-op
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import androidx.test.espresso.UiController
|
||||
import org.maplibre.android.camera.CameraUpdateFactory
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction.invoke
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class TransformTest : EspressoTest() {
|
||||
|
||||
companion object {
|
||||
val initialCameraUpdate = CameraUpdateFactory.newLatLngZoom(LatLng(12.0, 12.0), 12.0)!!
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mapboxMapScrollByWithPadding() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(initialCameraUpdate)
|
||||
maplibreMap.scrollBy(400.0f, 0.0f)
|
||||
val expectedCameraPosition = maplibreMap.cameraPosition
|
||||
|
||||
maplibreMap.moveCamera(initialCameraUpdate)
|
||||
maplibreMap.setPadding(250, 250, 0, 0)
|
||||
maplibreMap.scrollBy(400.0f, 0.0f)
|
||||
val actualCameraPosition = maplibreMap.cameraPosition
|
||||
|
||||
assertEquals("Camera position should match", expectedCameraPosition, actualCameraPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
package org.maplibre.android.maps
|
||||
|
||||
import android.graphics.PointF
|
||||
import androidx.test.espresso.UiController
|
||||
import org.maplibre.android.camera.CameraUpdateFactory
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.geometry.LatLngBounds
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction.invoke
|
||||
import org.maplibre.android.testapp.activity.BaseTest
|
||||
import org.maplibre.android.testapp.activity.espresso.PixelTestActivity
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class VisibleRegionTest : BaseTest() {
|
||||
|
||||
override fun getActivityClass(): Class<*> {
|
||||
return PixelTestActivity::class.java
|
||||
}
|
||||
|
||||
override
|
||||
fun beforeTest() {
|
||||
super.beforeTest()
|
||||
mapView = (rule.activity as PixelTestActivity).mapView
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedVisibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(
|
||||
mapView.width / 4,
|
||||
mapView.height / 4,
|
||||
mapView.width / 4,
|
||||
mapView.height / 4
|
||||
)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 1)
|
||||
assertTrue(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedLeftVisibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(mapView.width / 4, 0, 0, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedTopVisibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, mapView.height / 4, 0, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedRightVisibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, 0, mapView.width / 4, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedBottomVisibleRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, 0, 0, mapView.height / 4)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedVisibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(
|
||||
mapView.width / 4,
|
||||
mapView.height / 4,
|
||||
mapView.width / 4,
|
||||
mapView.height / 4
|
||||
)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 1)
|
||||
assertTrue(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedLeftVisibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(mapView.width / 4, 0, 0, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedTopVisibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { ui: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
ui.loopMainThreadForAtLeast(5000)
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, mapView.height / 4, 0, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedRightVisibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, 0, mapView.width / 4, 0)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun paddedBottomVisibleRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
|
||||
maplibreMap.setPadding(0, 0, 0, mapView.height / 4)
|
||||
|
||||
val visibleRegion = maplibreMap.projection.getVisibleRegion(false)
|
||||
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
|
||||
assertTrue(filtered.size == 6)
|
||||
assertFalse(filtered.contains(maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRotatedRegionTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val d = Math.min(maplibreMap.width, maplibreMap.height) / 4
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
|
||||
)
|
||||
|
||||
for (bearing in 45 until 360 step 45) {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRotatedRegionOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val d = Math.min(maplibreMap.width, maplibreMap.height) / 4
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
|
||||
)
|
||||
|
||||
for (bearing in 45 until 360 step 45) {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRegionWithBoundsEqualTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
maplibreMap.projection.getVisibleCoordinateBounds(bounds)
|
||||
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngBounds == visibleRegion.latLngBounds)
|
||||
assertTrue(latLngs.all { latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRegionBoundsOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
|
||||
.also { it.longitude += 360 },
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
|
||||
maplibreMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
|
||||
)
|
||||
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
maplibreMap.projection.getVisibleCoordinateBounds(bounds)
|
||||
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
|
||||
assertTrue(latLngs.all { latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRegionBoundsOverDatelineLatitudeZeroTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
|
||||
val shift = maplibreMap.getLatLngFromScreenCoords(0f, 0f)
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(0.0, 180.0 - shift.longitude)))
|
||||
|
||||
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
maplibreMap.projection.getVisibleCoordinateBounds(bounds)
|
||||
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngBounds == visibleRegion.latLngBounds)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRotatedRegionBoundEqualTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
|
||||
val d = Math.min(maplibreMap.width, maplibreMap.height) / 4
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
|
||||
)
|
||||
|
||||
for (bearing in 45 until 360 step 45) {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
|
||||
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
maplibreMap.projection.getVisibleCoordinateBounds(bounds)
|
||||
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
|
||||
val visibleRegion = maplibreMap.projection.visibleRegion
|
||||
assertTrue(latLngBounds == visibleRegion.latLngBounds)
|
||||
assertTrue(latLngs.all { latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun visibleRotatedRegionBoundsOverDatelineTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { _: UiController, maplibreMap: MapLibreMap ->
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 179.0), 8.0))
|
||||
val d = Math.min(maplibreMap.width, maplibreMap.height) / 4
|
||||
val latLngs = listOf(
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
|
||||
maplibreMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
|
||||
)
|
||||
|
||||
for (bearing in 45 until 360 step 45) {
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()))
|
||||
val bounds = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
maplibreMap.projection.getVisibleCoordinateBounds(bounds)
|
||||
val latLngBounds = LatLngBounds.from(bounds[0], bounds[1], bounds[2], bounds[3])
|
||||
assertTrue(latLngs.all { latLngBounds.contains(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MapLibreMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng {
|
||||
return this.projection.fromScreenLocation(PointF(x, y))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.maplibre.android.offline
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import com.mapbox.geojson.Point
|
||||
import org.maplibre.android.log.Logger
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
/**
|
||||
* Integration test that validates downloading an offline region from a point geometry at zoomlevel 17
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class OfflineDownloadTest : OfflineRegion.OfflineRegionObserver {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
private val countDownLatch = CountDownLatch(1)
|
||||
private lateinit var offlineRegion: OfflineRegion
|
||||
|
||||
@Test(timeout = 60000)
|
||||
fun offlineDownload() {
|
||||
rule.runOnUiThreadActivity {
|
||||
OfflineManager.getInstance(rule.activity).createOfflineRegion(
|
||||
createTestRegionDefinition(),
|
||||
ByteArray(0),
|
||||
object : OfflineManager.CreateOfflineRegionCallback {
|
||||
override fun onCreate(region: OfflineRegion) {
|
||||
offlineRegion = region
|
||||
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
|
||||
offlineRegion.setObserver(this@OfflineDownloadTest)
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
Logger.e(TAG, "Error while creating offline region: $error")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (!countDownLatch.await(60, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStatusChanged(status: OfflineRegionStatus) {
|
||||
Logger.i(TAG, "Download percentage ${100.0 * status.completedResourceCount / status.requiredResourceCount}")
|
||||
if (status.isComplete) {
|
||||
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(error: OfflineRegionError) {
|
||||
Logger.e(TAG, "Error while downloading offline region: $error")
|
||||
}
|
||||
|
||||
override fun mapboxTileCountLimitExceeded(limit: Long) {
|
||||
Logger.e(TAG, "Tile count limited exceeded: $limit")
|
||||
}
|
||||
|
||||
private fun createTestRegionDefinition(): OfflineRegionDefinition {
|
||||
return OfflineGeometryRegionDefinition(
|
||||
Style.getPredefinedStyle("Streets"),
|
||||
Point.fromLngLat(50.847857, 4.360137),
|
||||
17.0,
|
||||
17.0,
|
||||
1.0f,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "OfflineDownloadTest"
|
||||
}
|
||||
}
|
||||
|
||||
fun ActivityTestRule<*>.runOnUiThreadActivity(runnable: () -> Unit) = activity.runOnUiThread(runnable)
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.maplibre.android.snapshotter
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.camera.CameraPosition
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.style.layers.BackgroundLayer
|
||||
import org.maplibre.android.style.layers.PropertyFactory
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
/**
|
||||
* Integration test that validates if a snapshotter creation
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class MapSnapshotterTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
private val countDownLatch = CountDownLatch(1)
|
||||
|
||||
@Test
|
||||
fun mapSnapshotter() {
|
||||
var mapSnapshotter: MapSnapshotter?
|
||||
rule.activity.runOnUiThread {
|
||||
val bg = BackgroundLayer("rand_tint")
|
||||
bg.setProperties(PropertyFactory.backgroundColor("rgba(255,128,0,0.7)"))
|
||||
val options = MapSnapshotter.Options(512, 512)
|
||||
.withPixelRatio(1.0f)
|
||||
.withStyleBuilder(
|
||||
Style.Builder().fromUri(Style.getPredefinedStyle("Satellite Hybrid"))
|
||||
.withLayerAbove(bg, "country-label")
|
||||
)
|
||||
.withCameraPosition(
|
||||
CameraPosition.Builder()
|
||||
.zoom(12.0)
|
||||
.target(LatLng(51.145495, 5.742234))
|
||||
.build()
|
||||
)
|
||||
mapSnapshotter = MapSnapshotter(rule.activity, options)
|
||||
mapSnapshotter!!.start(
|
||||
{
|
||||
assertNotNull(it)
|
||||
assertNotNull(it.bitmap)
|
||||
countDownLatch.countDown()
|
||||
},
|
||||
{
|
||||
Assert.fail(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (!countDownLatch.await(30, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.maplibre.android.style.sources
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
@UiThreadTest
|
||||
class RasterSourceTest {
|
||||
@Test
|
||||
fun rasterSource_constructor() {
|
||||
val tiles = arrayOf("https://example.com")
|
||||
val tileSet = TileSet("2.1.0", *tiles)
|
||||
|
||||
// set bounds on tile set
|
||||
val bounds = floatArrayOf(-180.0f, -85.05113f, 180.0f, 85.05113f)
|
||||
tileSet.setBounds(*bounds)
|
||||
// create RasterSource
|
||||
RasterSource("source_id", tileSet)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.maplibre.android.testapp.action;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
public class MapLibreMapAction implements ViewAction {
|
||||
|
||||
private OnInvokeActionListener invokeViewAction;
|
||||
private MapLibreMap maplibreMap;
|
||||
|
||||
public MapLibreMapAction(OnInvokeActionListener invokeViewAction, MapLibreMap maplibreMap) {
|
||||
this.invokeViewAction = invokeViewAction;
|
||||
this.maplibreMap = maplibreMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
invokeViewAction.onInvokeAction(uiController, maplibreMap);
|
||||
}
|
||||
|
||||
public static void invoke(MapLibreMap maplibreMap, OnInvokeActionListener invokeViewAction) {
|
||||
onView(withId(android.R.id.content)).perform(new MapLibreMapAction(invokeViewAction, maplibreMap));
|
||||
}
|
||||
|
||||
public interface OnInvokeActionListener {
|
||||
void onInvokeAction(@NonNull UiController uiController, @NonNull MapLibreMap maplibreMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package org.maplibre.android.testapp.action;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
|
||||
public class OrientationAction implements ViewAction {
|
||||
|
||||
private final int orientation;
|
||||
|
||||
private OrientationAction(int orientation) {
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
public static ViewAction orientationLandscape() {
|
||||
return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
|
||||
public static ViewAction orientationPortrait() {
|
||||
return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
public static ViewAction orientationLandscapeReverse() {
|
||||
return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||
}
|
||||
|
||||
public static ViewAction orientationPortraitReverse() {
|
||||
return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "change orientation to " + orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadUntilIdle();
|
||||
Activity activity = getActivity(view.getContext());
|
||||
if (activity == null && view instanceof ViewGroup) {
|
||||
ViewGroup v = (ViewGroup) view;
|
||||
int c = v.getChildCount();
|
||||
for (int i = 0; i < c && activity == null; ++i) {
|
||||
activity = getActivity(v.getChildAt(i).getContext());
|
||||
}
|
||||
}
|
||||
activity.setRequestedOrientation(orientation);
|
||||
}
|
||||
|
||||
public static void invoke(ViewAction action) {
|
||||
onView(isRoot()).perform(action);
|
||||
}
|
||||
|
||||
private Activity getActivity(Context context) {
|
||||
while (context instanceof ContextWrapper) {
|
||||
if (context instanceof Activity) {
|
||||
return (Activity) context;
|
||||
}
|
||||
context = ((ContextWrapper) context).getBaseContext();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.maplibre.android.testapp.action;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
|
||||
public final class WaitAction implements ViewAction {
|
||||
|
||||
private final long loopTime;
|
||||
|
||||
public WaitAction(long loopTime) {
|
||||
this.loopTime = loopTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadForAtLeast(loopTime);
|
||||
}
|
||||
|
||||
public static void invoke(long loopTime) {
|
||||
onView(isRoot()).perform(new WaitAction(loopTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.maplibre.android.testapp.activity;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
|
||||
import org.maplibre.android.AppCenter;
|
||||
import org.maplibre.android.MapLibre;
|
||||
import org.maplibre.android.maps.MapView;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
import org.maplibre.android.testapp.R;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
/**
|
||||
* Base class for all Activity test hooking into an existing Activity that will load style.
|
||||
*/
|
||||
public abstract class BaseTest extends AppCenter {
|
||||
|
||||
private static final int WAIT_TIMEOUT = 30; //seconds
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule rule = new ActivityTestRule<>(getActivityClass());
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule grantLocationPermissionRule = GrantPermissionRule
|
||||
.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
|
||||
protected MapLibreMap maplibreMap;
|
||||
protected MapView mapView;
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@Before
|
||||
@CallSuper
|
||||
public void beforeTest() {
|
||||
initialiseMap();
|
||||
holdTestRunnerForStyleLoad();
|
||||
}
|
||||
|
||||
@After
|
||||
@CallSuper
|
||||
public void afterTest() {
|
||||
super.afterTest();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@CallSuper
|
||||
protected void initMap(MapLibreMap maplibreMap) {
|
||||
this.maplibreMap = maplibreMap;
|
||||
maplibreMap.getStyle(style -> latch.countDown());
|
||||
}
|
||||
|
||||
protected void validateTestSetup() {
|
||||
if (!MapLibre.isConnected()) {
|
||||
Timber.e("Not connected to the internet while running test");
|
||||
}
|
||||
assertNotNull("MapView isn't initialised", mapView);
|
||||
assertNotNull("MapLibreMap isn't initialised", maplibreMap);
|
||||
assertNotNull("Style isn't initialised", maplibreMap.getStyle());
|
||||
assertTrue("Style isn't fully loaded", maplibreMap.getStyle().isFullyLoaded());
|
||||
}
|
||||
|
||||
protected abstract Class getActivityClass();
|
||||
|
||||
private void initialiseMap() {
|
||||
try {
|
||||
rule.runOnUiThread(() -> {
|
||||
mapView = rule.getActivity().findViewById(R.id.mapView);
|
||||
if (mapView != null) {
|
||||
mapView.getMapAsync(this::initMap);
|
||||
} else {
|
||||
Timber.w("Skipping map load test since mapView is not found.");
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void holdTestRunnerForStyleLoad() {
|
||||
boolean interrupted;
|
||||
try {
|
||||
interrupted = latch.await(WAIT_TIMEOUT, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignore) {
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
if (!interrupted) {
|
||||
Timber.e("Timeout occurred for %s", testName.getMethodName());
|
||||
validateTestSetup();
|
||||
}
|
||||
}
|
||||
|
||||
protected Context getContext() {
|
||||
return rule.getActivity();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.maplibre.android.testapp.activity
|
||||
|
||||
import androidx.annotation.UiThread
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.testapp.activity.espresso.EspressoTestActivity
|
||||
|
||||
/**
|
||||
* Base class for all tests using EspressoTestActivity as wrapper.
|
||||
*
|
||||
*
|
||||
* Loads "assets/streets.json" as style.
|
||||
*
|
||||
*/
|
||||
open class EspressoTest : BaseTest() {
|
||||
override fun getActivityClass(): Class<*> {
|
||||
return EspressoTestActivity::class.java
|
||||
}
|
||||
|
||||
@UiThread
|
||||
override fun initMap(maplibreMap: MapLibreMap) {
|
||||
maplibreMap.setStyle(Style.Builder().fromUri("asset://streets.json"))
|
||||
super.initMap(maplibreMap)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.maplibre.android.testapp.annotations;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
|
||||
import org.maplibre.android.annotations.Icon;
|
||||
import org.maplibre.android.annotations.IconFactory;
|
||||
import org.maplibre.android.annotations.Marker;
|
||||
import org.maplibre.android.annotations.MarkerOptions;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.maps.IconManagerResolver;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.IconUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Tests integration between Icons and Markers
|
||||
*/
|
||||
public class IconTest extends EspressoTest {
|
||||
|
||||
private Map<Icon, Integer> iconMap;
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
super.beforeTest();
|
||||
iconMap = new IconManagerResolver(maplibreMap).getIconMap();
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAddSameIconMarker() {
|
||||
validateTestSetup();
|
||||
Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker();
|
||||
maplibreMap.addMarker(new MarkerOptions().position(new LatLng()));
|
||||
maplibreMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
|
||||
assertEquals(1, iconMap.size());
|
||||
assertEquals(2, iconMap.get(defaultMarker), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAddDifferentIconMarker() {
|
||||
validateTestSetup();
|
||||
Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.maplibre_logo_icon);
|
||||
maplibreMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
|
||||
maplibreMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
|
||||
assertEquals(iconMap.size(), 2);
|
||||
assertTrue(iconMap.containsKey(icon));
|
||||
assertTrue(iconMap.get(icon) == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAddRemoveIconMarker() {
|
||||
validateTestSetup();
|
||||
Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.maplibre_logo_icon);
|
||||
Marker marker = maplibreMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
|
||||
maplibreMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
|
||||
assertEquals(iconMap.size(), 2);
|
||||
assertTrue(iconMap.containsKey(icon));
|
||||
assertTrue(iconMap.get(icon) == 1);
|
||||
|
||||
maplibreMap.removeMarker(marker);
|
||||
assertEquals(iconMap.size(), 1);
|
||||
assertFalse(iconMap.containsKey(icon));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAddRemoveDefaultMarker() {
|
||||
validateTestSetup();
|
||||
Marker marker = maplibreMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
|
||||
assertEquals(iconMap.size(), 1);
|
||||
|
||||
maplibreMap.removeMarker(marker);
|
||||
assertEquals(iconMap.size(), 0);
|
||||
|
||||
maplibreMap.addMarker(new MarkerOptions().position(new LatLng()));
|
||||
assertEquals(iconMap.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testAddRemoveMany() {
|
||||
validateTestSetup();
|
||||
Activity activity = rule.getActivity();
|
||||
IconFactory iconFactory = IconFactory.getInstance(activity);
|
||||
|
||||
// add 2 default icon markers
|
||||
Marker defaultMarkerOne = maplibreMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
|
||||
Marker defaultMarkerTwo = maplibreMap.addMarker(new MarkerOptions().position(new LatLng(2, 1)));
|
||||
|
||||
// add 4 unique icon markers
|
||||
maplibreMap.addMarker(new MarkerOptions()
|
||||
.icon(iconFactory.fromResource(R.drawable.maplibre_logo_icon))
|
||||
.position(new LatLng(3, 1))
|
||||
);
|
||||
maplibreMap.addMarker(new MarkerOptions()
|
||||
.icon(iconFactory.fromResource(R.drawable.maplibre_compass_icon))
|
||||
.position(new LatLng(4, 1))
|
||||
);
|
||||
maplibreMap.addMarker(new MarkerOptions()
|
||||
.icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars,
|
||||
ResourcesCompat.getColor(activity.getResources(),
|
||||
R.color.blueAccent, activity.getTheme())))
|
||||
.position(new LatLng(5, 1))
|
||||
);
|
||||
maplibreMap.addMarker(new MarkerOptions()
|
||||
.icon(iconFactory.fromResource(R.drawable.ic_android))
|
||||
.position(new LatLng(6, 1))
|
||||
);
|
||||
|
||||
assertEquals("Amount of icons should match 5", 5, iconMap.size());
|
||||
assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0);
|
||||
|
||||
maplibreMap.removeMarker(defaultMarkerOne);
|
||||
|
||||
assertEquals("Amount of icons should match 5", 5, iconMap.size());
|
||||
assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0);
|
||||
|
||||
maplibreMap.removeMarker(defaultMarkerTwo);
|
||||
|
||||
assertEquals("Amount of icons should match 4", 4, iconMap.size());
|
||||
assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker()));
|
||||
|
||||
maplibreMap.clear();
|
||||
assertEquals("Amount of icons should match 0", 0, iconMap.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.maplibre.android.testapp.annotations;
|
||||
|
||||
import org.maplibre.android.annotations.Marker;
|
||||
import org.maplibre.android.annotations.MarkerOptions;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.TestConstants;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MarkerTest extends EspressoTest {
|
||||
|
||||
private Marker marker;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void addMarkerTest() {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
assertEquals("Markers should be empty", 0, mapboxMap.getMarkers().size());
|
||||
|
||||
MarkerOptions options = new MarkerOptions();
|
||||
options.setPosition(new LatLng());
|
||||
options.setSnippet(TestConstants.TEXT_MARKER_SNIPPET);
|
||||
options.setTitle(TestConstants.TEXT_MARKER_TITLE);
|
||||
marker = mapboxMap.addMarker(options);
|
||||
|
||||
assertEquals("Markers size should be 1, ", 1, mapboxMap.getMarkers().size());
|
||||
assertEquals("Marker id should be 0", 0, marker.getId());
|
||||
assertEquals("Marker target should match", new LatLng(), marker.getPosition());
|
||||
assertEquals("Marker snippet should match", TestConstants.TEXT_MARKER_SNIPPET, marker.getSnippet());
|
||||
assertEquals("Marker target should match", TestConstants.TEXT_MARKER_TITLE, marker.getTitle());
|
||||
mapboxMap.clear();
|
||||
assertEquals("Markers should be empty", 0, mapboxMap.getMarkers().size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void showInfoWindowTest() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
final MarkerOptions options = new MarkerOptions();
|
||||
options.setPosition(new LatLng());
|
||||
options.setSnippet(TestConstants.TEXT_MARKER_SNIPPET);
|
||||
options.setTitle(TestConstants.TEXT_MARKER_TITLE);
|
||||
marker = mapboxMap.addMarker(options);
|
||||
mapboxMap.selectMarker(marker);
|
||||
});
|
||||
onView(withText(TestConstants.TEXT_MARKER_TITLE)).check(matches(isDisplayed()));
|
||||
onView(withText(TestConstants.TEXT_MARKER_SNIPPET)).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.maplibre.android.testapp.annotations;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.maplibre.android.annotations.Polygon;
|
||||
import org.maplibre.android.annotations.PolygonOptions;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class PolygonTest extends EspressoTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void addPolygonTest() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLngOne = new LatLng();
|
||||
LatLng latLngTwo = new LatLng(1, 0);
|
||||
LatLng latLngThree = new LatLng(1, 1);
|
||||
|
||||
assertEquals("Polygons should be empty", 0, mapboxMap.getPolygons().size());
|
||||
|
||||
final PolygonOptions options = new PolygonOptions();
|
||||
options.strokeColor(Color.BLUE);
|
||||
options.fillColor(Color.RED);
|
||||
options.add(latLngOne);
|
||||
options.add(latLngTwo);
|
||||
options.add(latLngThree);
|
||||
Polygon polygon = mapboxMap.addPolygon(options);
|
||||
|
||||
assertEquals("Polygons should be 1", 1, mapboxMap.getPolygons().size());
|
||||
assertEquals("Polygon id should be 0", 0, polygon.getId());
|
||||
assertEquals("Polygon points size should match", 3, polygon.getPoints().size());
|
||||
assertEquals("Polygon stroke color should match", Color.BLUE, polygon.getStrokeColor());
|
||||
assertEquals("Polygon target should match", Color.RED, polygon.getFillColor());
|
||||
mapboxMap.clear();
|
||||
assertEquals("Polygons should be empty", 0, mapboxMap.getPolygons().size());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.maplibre.android.testapp.annotations;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.maplibre.android.annotations.Polyline;
|
||||
import org.maplibre.android.annotations.PolylineOptions;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class PolylineTest extends EspressoTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void addPolylineTest() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLngOne = new LatLng();
|
||||
LatLng latLngTwo = new LatLng(1, 0);
|
||||
|
||||
assertEquals("Polygons should be empty", 0, mapboxMap.getPolygons().size());
|
||||
|
||||
final PolylineOptions options = new PolylineOptions();
|
||||
options.color(Color.BLUE);
|
||||
options.add(latLngOne);
|
||||
options.add(latLngTwo);
|
||||
Polyline polyline = mapboxMap.addPolyline(options);
|
||||
|
||||
assertEquals("Polylines should be 1", 1, mapboxMap.getPolylines().size());
|
||||
assertEquals("Polyline id should be 0", 0, polyline.getId());
|
||||
assertEquals("Polyline points size should match", 2, polyline.getPoints().size());
|
||||
assertEquals("Polyline stroke color should match", Color.BLUE, polyline.getColor());
|
||||
mapboxMap.clear();
|
||||
assertEquals("Polyline should be empty", 0, mapboxMap.getPolylines().size());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.maplibre.android.testapp.camera;
|
||||
|
||||
import org.maplibre.android.camera.CameraUpdate;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
|
||||
public class CameraAnimateTest extends CameraTest {
|
||||
@Override
|
||||
void executeCameraMovement(CameraUpdate cameraUpdate, MapLibreMap.CancelableCallback callback) {
|
||||
maplibreMap.animateCamera(cameraUpdate, callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.maplibre.android.testapp.camera;
|
||||
|
||||
import org.maplibre.android.camera.CameraUpdate;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
|
||||
public class CameraEaseTest extends CameraTest {
|
||||
|
||||
@Override
|
||||
void executeCameraMovement(CameraUpdate cameraUpdate, MapLibreMap.CancelableCallback callback) {
|
||||
maplibreMap.easeCamera(cameraUpdate, callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package org.maplibre.android.testapp.camera;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.camera.CameraPosition;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.geometry.LatLngBounds;
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.espresso.DeviceIndependentTestActivity;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class CameraForTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForLatLngBounds() {
|
||||
validateTestSetup();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(10, 10, -10, -10));
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForLatLngBoundsPadding() {
|
||||
validateTestSetup();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5});
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForLatLngBoundsBearing() {
|
||||
validateTestSetup();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(10, 10, -10, -10), 45, 0);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForLatLngBoundsTilt() {
|
||||
validateTestSetup();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(10, 10, -10, -10), 0, 45);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForLatLngBoundsAll() {
|
||||
validateTestSetup();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForLatLngBounds(
|
||||
LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometry() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition));
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<List<Point>> getPolygonDefinition() {
|
||||
return new ArrayList<List<Point>>() {
|
||||
{
|
||||
add(new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(10, 10));
|
||||
add(Point.fromLngLat(-10, 10));
|
||||
add(Point.fromLngLat(-10, -10));
|
||||
add(Point.fromLngLat(10, -10));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometryPadding() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
|
||||
new int[] {5, 5, 5, 5});
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometryBearing() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometryTilt() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometryAll() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
|
||||
new int[] {5, 5, 5, 5}, 45, 45);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testGetCameraForGeometryDeprecatedApi() {
|
||||
validateTestSetup();
|
||||
List<List<Point>> polygonDefinition = getPolygonDefinition();
|
||||
CameraPosition actualPosition = maplibreMap.getCameraForGeometry(
|
||||
Polygon.fromLngLats(polygonDefinition),
|
||||
new int[] {5, 5, 5, 5},
|
||||
45, 0);
|
||||
CameraPosition expectedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build();
|
||||
assertEquals("Latitude should match",
|
||||
expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
|
||||
assertEquals("Longitude should match",
|
||||
expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
|
||||
assertEquals("Zoom should match",
|
||||
expectedPosition.zoom, actualPosition.zoom, 0.01f);
|
||||
assertEquals("Tilt should match",
|
||||
expectedPosition.tilt, actualPosition.tilt, 0.01f);
|
||||
assertEquals("Bearing should match",
|
||||
expectedPosition.bearing, actualPosition.bearing, 0.01f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return DeviceIndependentTestActivity.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
package org.maplibre.android.testapp.camera;
|
||||
|
||||
import org.maplibre.android.camera.CameraUpdate;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
|
||||
public class CameraMoveTest extends CameraTest {
|
||||
@Override
|
||||
void executeCameraMovement(CameraUpdate cameraUpdate, MapLibreMap.CancelableCallback callback) {
|
||||
maplibreMap.moveCamera(cameraUpdate, callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
package org.maplibre.android.testapp.camera;
|
||||
|
||||
import org.maplibre.android.camera.CameraPosition;
|
||||
import org.maplibre.android.camera.CameraUpdate;
|
||||
import org.maplibre.android.camera.CameraUpdateFactory;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.geometry.LatLngBounds;
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.espresso.DeviceIndependentTestActivity;
|
||||
import org.maplibre.android.testapp.utils.TestConstants;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public abstract class CameraTest extends BaseTest {
|
||||
|
||||
private CountDownLatch latch;
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return DeviceIndependentTestActivity.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTest() {
|
||||
super.beforeTest();
|
||||
latch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCameraPositionTarget() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
float zoom = 1.0f;
|
||||
LatLng moveTarget = new LatLng(1, 1);
|
||||
CameraPosition initialPosition = new CameraPosition.Builder().target(
|
||||
new LatLng()).zoom(zoom).bearing(0).tilt(0).padding(new double[4]).build();
|
||||
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
|
||||
assertEquals("Default camera position should match default", cameraPosition, initialPosition);
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.newLatLng(moveTarget), new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCameraPositionTargetZoom() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
final float moveZoom = 15.5f;
|
||||
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom),
|
||||
new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToCameraPosition() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
|
||||
final float moveZoom = 15.5f;
|
||||
final float moveTilt = 45.5f;
|
||||
final float moveBearing = 12.5f;
|
||||
final double[] movePadding = new double[] {0, 500, 350, 1};
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.newCameraPosition(
|
||||
new CameraPosition.Builder()
|
||||
.target(moveTarget)
|
||||
.zoom(moveZoom)
|
||||
.tilt(moveTilt)
|
||||
.bearing(moveBearing)
|
||||
.padding(movePadding)
|
||||
.build()),
|
||||
new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToBounds() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
final LatLng centerBounds = new LatLng(1, 1);
|
||||
LatLng cornerOne = new LatLng();
|
||||
LatLng cornerTwo = new LatLng(2, 2);
|
||||
final LatLngBounds.Builder builder = new LatLngBounds.Builder();
|
||||
builder.include(cornerOne);
|
||||
builder.include(cornerTwo);
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
|
||||
new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToZoomIn() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
float zoom = 1.0f;
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.zoomIn(), new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToZoomOut() throws InterruptedException {
|
||||
float zoom = 10.0f;
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) ->
|
||||
executeCameraMovement(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom),
|
||||
new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
|
||||
latch = new CountDownLatch(1);
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
executeCameraMovement(CameraUpdateFactory.zoomOut(), new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToZoomBy() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
float zoom = 1.0f;
|
||||
final float zoomBy = 2.45f;
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.zoomBy(zoomBy), new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToZoomTo() throws InterruptedException {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
final float zoomTo = 2.45f;
|
||||
|
||||
executeCameraMovement(CameraUpdateFactory.zoomTo(zoomTo), new MapLibreMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
Assert.fail("timeout");
|
||||
}
|
||||
}
|
||||
|
||||
abstract void executeCameraMovement(CameraUpdate cameraUpdate, MapLibreMap.CancelableCallback callback);
|
||||
|
||||
private void verifyCameraPosition(MapLibreMap maplibreMap, LatLng moveTarget, double moveZoom, double moveBearing,
|
||||
double moveTilt, double[] padding) {
|
||||
CameraPosition cameraPosition = maplibreMap.getCameraPosition();
|
||||
assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
|
||||
moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
|
||||
assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
|
||||
moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
|
||||
assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
|
||||
assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
|
||||
assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
|
||||
assertArrayEquals("Moved padding should match", cameraPosition.padding, padding, TestConstants.PADDING_DELTA);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.maplibre.android.testapp.fragment
|
||||
|
||||
import androidx.test.espresso.Espresso
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.filters.LargeTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.maplayout.MapInDialogActivity
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Regression test that validates that a map inside a DialogFragment can be opened and closed.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
@LargeTest
|
||||
class MapDialogFragmentTest : AppCenter() {
|
||||
|
||||
@get:Rule
|
||||
var activityRule: ActivityTestRule<MapInDialogActivity> = ActivityTestRule(MapInDialogActivity::class.java)
|
||||
|
||||
@Test
|
||||
@Ignore("Probably does not work")
|
||||
fun openCloseDialog() {
|
||||
onView(withId(R.id.button_open_dialog)).perform(click())
|
||||
Thread.sleep(2500)
|
||||
Espresso.pressBack()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.maplibre.android.testapp.geometry;
|
||||
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.PropertyFactory;
|
||||
import org.maplibre.android.style.layers.SymbolLayer;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static com.mapbox.geojson.Feature.fromGeometry;
|
||||
import static com.mapbox.geojson.FeatureCollection.fromFeatures;
|
||||
import static com.mapbox.geojson.GeometryCollection.fromGeometries;
|
||||
import static com.mapbox.geojson.LineString.fromLngLats;
|
||||
import static com.mapbox.geojson.MultiLineString.fromLineString;
|
||||
import static com.mapbox.geojson.MultiPolygon.fromPolygon;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* Instrumentation test to validate java geojson conversion to c++
|
||||
*/
|
||||
public class GeoJsonConversionTest extends EspressoTest {
|
||||
|
||||
// Regression test for #12343
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testEmptyFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList()))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testPointFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testMultiPointFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testPolygonFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList()))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testMultiPolygonFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList())))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineStringFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testMultiLineStringFeatureCollection() {
|
||||
validateTestSetup();
|
||||
maplibreMap.getStyle().addSource(
|
||||
new GeoJsonSource("test-id",
|
||||
fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList())))))
|
||||
)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNegativeNumberPropertyConversion() {
|
||||
validateTestSetup();
|
||||
onView(isRoot()).perform(new MapLibreMapAction((uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng();
|
||||
Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
|
||||
|
||||
JsonArray foregroundJsonArray = new JsonArray();
|
||||
foregroundJsonArray.add(0f);
|
||||
foregroundJsonArray.add(-3f);
|
||||
feature.addProperty("property", foregroundJsonArray);
|
||||
|
||||
GeoJsonSource source = new GeoJsonSource("source", feature);
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source")
|
||||
.withProperties(
|
||||
PropertyFactory.iconOffset(Expression.get("property")),
|
||||
PropertyFactory.iconImage("zoo-15")
|
||||
);
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng)).isEmpty());
|
||||
}, maplibreMap));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.maplibre.android.testapp.geometry;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.maplibre.android.camera.CameraUpdateFactory;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.geometry.LatLngBounds;
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction;
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.feature.QueryRenderedFeaturesBoxHighlightActivity;
|
||||
import org.maplibre.android.testapp.utils.TestConstants;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Instrumentation test to validate integration of LatLngBounds
|
||||
*/
|
||||
public class LatLngBoundsTest extends BaseTest {
|
||||
|
||||
private static final double MAP_BEARING = 50;
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return QueryRenderedFeaturesBoxHighlightActivity.class;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLatLngBounds() {
|
||||
// regression test for #9322
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLngBounds bounds = new LatLngBounds.Builder()
|
||||
.include(new LatLng(48.8589506, 2.2773457))
|
||||
.include(new LatLng(47.2383171, -1.6309316))
|
||||
.build();
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLatLngBoundsBearing() {
|
||||
// regression test for #12549
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLngBounds bounds = new LatLngBounds.Builder()
|
||||
.include(new LatLng(48.8589506, 2.2773457))
|
||||
.include(new LatLng(47.2383171, -1.6309316))
|
||||
.build();
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(MAP_BEARING));
|
||||
assertEquals(
|
||||
"Initial bearing should match for latlngbounds",
|
||||
mapboxMap.getCameraPosition().bearing,
|
||||
MAP_BEARING,
|
||||
TestConstants.BEARING_DELTA
|
||||
);
|
||||
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
|
||||
assertEquals("Bearing should match after resetting latlngbounds",
|
||||
mapboxMap.getCameraPosition().bearing,
|
||||
MAP_BEARING,
|
||||
TestConstants.BEARING_DELTA);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package org.maplibre.android.testapp.maps
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.espresso.EspressoTestActivity
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class ImageMissingTest : AppCenter() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(EspressoTestActivity::class.java)
|
||||
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var latch: CountDownLatch
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
latch = CountDownLatch(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMissingImage() {
|
||||
rule.runOnUiThread {
|
||||
initMap(styleJson).addOnStyleImageMissingListener {
|
||||
assertEquals("missing-icon", it)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMissingImage_invalidSprite() {
|
||||
rule.runOnUiThread {
|
||||
initMap(styleJsonInvalidSprite).addOnStyleImageMissingListener {
|
||||
assertEquals("missing-icon", it)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch.await(10, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initMap(style: String): MapView {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
mapView.getMapAsync { it.setStyle(Style.Builder().fromJson(style)) }
|
||||
return mapView
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val styleJson =
|
||||
"""
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Streets",
|
||||
"sprite": "maptiler://sprites/streets/sprite",
|
||||
"glyphs": "maptiler://fonts/{fontstack}/{range}.pbf",
|
||||
"sources": {
|
||||
"point": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layers": [{
|
||||
"id": "bg",
|
||||
"type": "background",
|
||||
"paint": {
|
||||
"background-color": "#f00"
|
||||
}
|
||||
}, {
|
||||
"id": "point",
|
||||
"type": "circle",
|
||||
"source": "point",
|
||||
"paint": {
|
||||
"circle-radius": 100
|
||||
}
|
||||
}, {
|
||||
"id": "icon",
|
||||
"type": "symbol",
|
||||
"source": "point",
|
||||
"layout": {
|
||||
"icon-image": "missing-icon"
|
||||
}
|
||||
}]
|
||||
}
|
||||
"""
|
||||
|
||||
private const val styleJsonInvalidSprite =
|
||||
"""
|
||||
{
|
||||
"version": 8,
|
||||
"name": "Streets",
|
||||
"sprite": "maptiler://sprites/streets/sprite",
|
||||
"glyphs": "maptiler://fonts/{fontstack}/{range}.pbf",
|
||||
"sources": {
|
||||
"point": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layers": [{
|
||||
"id": "bg",
|
||||
"type": "background",
|
||||
"paint": {
|
||||
"background-color": "#f00"
|
||||
}
|
||||
}, {
|
||||
"id": "point",
|
||||
"type": "circle",
|
||||
"source": "point",
|
||||
"paint": {
|
||||
"circle-radius": 100
|
||||
}
|
||||
}, {
|
||||
"id": "icon",
|
||||
"type": "symbol",
|
||||
"source": "point",
|
||||
"layout": {
|
||||
"icon-image": "missing-icon"
|
||||
}
|
||||
}]
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package org.maplibre.android.testapp.maps
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.camera.CameraUpdateFactory
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.espresso.EspressoTestActivity
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class RemoveUnusedImagesTest : AppCenter() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(EspressoTestActivity::class.java)
|
||||
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var maplibreMap: MapLibreMap
|
||||
private val latch = CountDownLatch(1)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
rule.runOnUiThread {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
mapView.getMapAsync {
|
||||
maplibreMap = it
|
||||
maplibreMap.setStyle(Style.Builder().fromJson(styleJson))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveUnusedImagesUserProvidedListener() {
|
||||
var callbackLatch = CountDownLatch(2)
|
||||
rule.runOnUiThread {
|
||||
mapView.addOnStyleImageMissingListener {
|
||||
maplibreMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
|
||||
}
|
||||
|
||||
// Remove layer and source, so that rendered tiles are no longer used, therefore, map must
|
||||
// notify client about unused images.
|
||||
mapView.addOnDidBecomeIdleListener {
|
||||
maplibreMap.style!!.removeLayer("icon")
|
||||
maplibreMap.style!!.removeSource("geojson")
|
||||
}
|
||||
|
||||
mapView.addOnCanRemoveUnusedStyleImageListener {
|
||||
callbackLatch.countDown()
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
|
||||
mapView.addOnDidFinishRenderingFrameListener{ _, _, _ ->
|
||||
assertNotNull(maplibreMap.style!!.getImage("small"))
|
||||
assertNotNull(maplibreMap.style!!.getImage("large"))
|
||||
latch.countDown()
|
||||
}
|
||||
return@addOnCanRemoveUnusedStyleImageListener false
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch.await(5, TimeUnit.SECONDS) && !callbackLatch.await(5, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveUnusedImagesDefaultListener() {
|
||||
rule.runOnUiThread {
|
||||
mapView.addOnStyleImageMissingListener {
|
||||
maplibreMap.style!!.addImage(it, Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888))
|
||||
}
|
||||
|
||||
// Remove layer and source, so that rendered tiles are no longer used, thus
|
||||
// map must request removal of unused images.
|
||||
mapView.addOnDidBecomeIdleListener {
|
||||
maplibreMap.style!!.removeLayer("icon")
|
||||
maplibreMap.style!!.removeSource("geojson")
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 120.0), 8.0))
|
||||
|
||||
// Wait for the next frame and check that images were removed from the style.
|
||||
mapView.addOnDidFinishRenderingFrameListener { _, _, _ ->
|
||||
if (maplibreMap.style!!.getImage("small") == null && maplibreMap.style!!.getImage("large") == null) {
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch.await(5, TimeUnit.SECONDS)) {
|
||||
throw TimeoutException()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val styleJson =
|
||||
"""
|
||||
{
|
||||
"version": 8,
|
||||
"name": "MapLibre Streets",
|
||||
"sources": {
|
||||
"geojson": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"image": "small"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"image": "large"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"layers": [{
|
||||
"id": "bg",
|
||||
"type": "background",
|
||||
"paint": {
|
||||
"background-color": "#f00"
|
||||
}
|
||||
},{
|
||||
"id": "icon",
|
||||
"type": "symbol",
|
||||
"source": "geojson",
|
||||
"layout": {
|
||||
"icon-image": ["get", "image"]
|
||||
}
|
||||
}]
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.maplibre.android.testapp.maps
|
||||
|
||||
import android.view.TextureView
|
||||
import android.view.ViewGroup
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.maps.MapLibreMapOptions
|
||||
import org.maplibre.android.maps.renderer.glsurfaceview.MapLibreGLSurfaceView
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class RenderViewGetterTest : AppCenter() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
private lateinit var rootView: ViewGroup
|
||||
private lateinit var mapView: MapView
|
||||
private val latch: CountDownLatch = CountDownLatch(1)
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testGLSurfaceView() {
|
||||
rootView = rule.activity.findViewById(android.R.id.content)
|
||||
mapView = MapView(rule.activity)
|
||||
assertNotNull(mapView.renderView)
|
||||
assertTrue(mapView.renderView is MapLibreGLSurfaceView)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testTextureView() {
|
||||
rootView = rule.activity.findViewById(android.R.id.content)
|
||||
mapView = MapView(
|
||||
rule.activity,
|
||||
MapLibreMapOptions.createFromAttributes(rule.activity, null)
|
||||
.textureMode(true)
|
||||
)
|
||||
assertNotNull(mapView.renderView)
|
||||
assertTrue(mapView.renderView is TextureView)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package org.maplibre.android.testapp.maps
|
||||
|
||||
import android.graphics.PointF
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.geometry.LatLng
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.activity.espresso.DeviceIndependentTestActivity
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class ScreenCoordinateConversion : AppCenter() {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(DeviceIndependentTestActivity::class.java)
|
||||
|
||||
private lateinit var mapView: MapView
|
||||
private lateinit var latch: CountDownLatch
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
latch = CountDownLatch(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToScreenCoordinates() {
|
||||
rule.runOnUiThread {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
val expected = doubleArrayOf(261.6888889445351, 253.15541110551123, 267.37777788907033, 247.4627648056528)
|
||||
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
mapView.getMapAsync {
|
||||
val projection = it.projection
|
||||
projection.toScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
|
||||
// check all values
|
||||
assertTrue(expected.contentEquals(actual))
|
||||
// check first coordinate value
|
||||
val pointFirst = PointF(expected[0].toFloat(), expected[1].toFloat())
|
||||
val convertedFirst = projection.toScreenLocation(LatLng(1.0, 2.0))
|
||||
assertEquals(
|
||||
pointFirst.x,
|
||||
convertedFirst.x,
|
||||
DELTA_FLOAT
|
||||
)
|
||||
assertEquals(
|
||||
pointFirst.y,
|
||||
convertedFirst.y,
|
||||
DELTA_FLOAT
|
||||
)
|
||||
|
||||
// check second latlng value
|
||||
val pointSecond = PointF(expected[2].toFloat(), expected[3].toFloat())
|
||||
val convertedSecond = projection.toScreenLocation(LatLng(3.0, 4.0))
|
||||
assertEquals(
|
||||
pointSecond.x,
|
||||
convertedSecond.x,
|
||||
DELTA_FLOAT
|
||||
)
|
||||
assertEquals(
|
||||
pointSecond.y,
|
||||
convertedSecond.y,
|
||||
DELTA_FLOAT
|
||||
)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
latch.await(10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFromScreenCoordinates() {
|
||||
rule.runOnUiThread {
|
||||
mapView = rule.activity.findViewById(R.id.mapView)
|
||||
val expected = doubleArrayOf(66.2314571265913, -89.64843662311537, 65.94647142295494, -88.94531162999371)
|
||||
val actual = doubleArrayOf(0.0, 0.0, 0.0, 0.0)
|
||||
mapView.getMapAsync {
|
||||
val projection = it.projection
|
||||
projection.fromScreenLocations(doubleArrayOf(1.0, 2.0, 3.0, 4.0), actual)
|
||||
// check all values at once
|
||||
assertArrayEquals(expected, actual, DELTA_DOUBLE)
|
||||
|
||||
// check first latlng value
|
||||
val latLngFirst = LatLng(expected[0], expected[1])
|
||||
val convertedFirst = projection.fromScreenLocation(PointF(1.0f, 2.0f))
|
||||
assertEquals(
|
||||
latLngFirst.latitude,
|
||||
convertedFirst.latitude,
|
||||
DELTA_DOUBLE
|
||||
)
|
||||
assertEquals(
|
||||
latLngFirst.longitude,
|
||||
convertedFirst.longitude,
|
||||
DELTA_DOUBLE
|
||||
)
|
||||
|
||||
// check second latlng value
|
||||
val latLngSecond = LatLng(expected[2], expected[3])
|
||||
val convertedSecond = projection.fromScreenLocation(PointF(3.0f, 4.0f))
|
||||
assertEquals(
|
||||
latLngSecond.latitude,
|
||||
convertedSecond.latitude,
|
||||
DELTA_DOUBLE
|
||||
)
|
||||
assertEquals(
|
||||
latLngSecond.longitude,
|
||||
convertedSecond.longitude,
|
||||
DELTA_DOUBLE
|
||||
)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
latch.await(10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DELTA_DOUBLE = 0.000001
|
||||
const val DELTA_FLOAT = 0.000001f
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.maplibre.android.testapp.maps
|
||||
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.style.layers.SymbolLayer
|
||||
import org.maplibre.android.style.sources.GeoJsonSource
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class StyleLoadTest : EspressoTest() {
|
||||
|
||||
@Test
|
||||
fun updateSourceAfterStyleLoad() {
|
||||
validateTestSetup()
|
||||
MapLibreMapAction.invoke(maplibreMap) { uiController: UiController, maplibreMap: MapLibreMap ->
|
||||
val source = GeoJsonSource("id")
|
||||
val layer = SymbolLayer("id", "id")
|
||||
maplibreMap.setStyle(Style.Builder().withSource(source).withLayer(layer))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
maplibreMap.setStyle(Style.Builder().fromUrl(Style.getPredefinedStyle("Streets")))
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
source.setGeoJson("{}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package org.maplibre.android.testapp.maps.widgets;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.URLSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
import org.maplibre.android.style.sources.Source;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onData;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.Intents.intending;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.anything;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
|
||||
public class AttributionTest extends EspressoTest {
|
||||
|
||||
private URLSpan[] urlSpans;
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
super.beforeTest();
|
||||
Intents.init();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabled() {
|
||||
validateTestSetup();
|
||||
|
||||
// Default
|
||||
onView(withTagValue(is("attrView"))).check(matches(isDisplayed()));
|
||||
|
||||
// Disabled
|
||||
onView(withTagValue(is("attrView")))
|
||||
.perform(new DisableAction(maplibreMap))
|
||||
.check(matches(not(isDisplayed())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testMapboxStreetsMapboxAttributionLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
buildUrlSpans();
|
||||
}
|
||||
|
||||
// click on View to open dialog
|
||||
onView(withTagValue(is("attrView"))).perform(click());
|
||||
onView(withText(R.string.maplibre_attributionsDialogTitle)).check(matches(isDisplayed()));
|
||||
|
||||
// test for trigger url intent
|
||||
Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(urlSpans[0].getURL())));
|
||||
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
|
||||
|
||||
// click item and test for url
|
||||
onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(0).perform(click());
|
||||
intended(expectedIntent);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testMapboxStreetsOpenStreetMapAttributionLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
buildUrlSpans();
|
||||
}
|
||||
|
||||
// click on View to open dialog
|
||||
onView(withTagValue(is("attrView"))).perform(click());
|
||||
onView(withText(R.string.maplibre_attributionsDialogTitle)).check(matches(isDisplayed()));
|
||||
|
||||
// test for trigger url intent
|
||||
Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(urlSpans[1].getURL())));
|
||||
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
|
||||
|
||||
// click item and test for url
|
||||
onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(1).perform(click());
|
||||
intended(expectedIntent);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testImproveMapLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
buildUrlSpans();
|
||||
}
|
||||
|
||||
// click on View to open dialog
|
||||
onView(withTagValue(is("attrView"))).perform(click());
|
||||
onView(withText(R.string.maplibre_attributionsDialogTitle)).check(matches(isDisplayed()));
|
||||
|
||||
// test for trigger url intent
|
||||
Matcher<Intent> expectedIntent = hasAction(Intent.ACTION_VIEW);
|
||||
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
|
||||
|
||||
// click item and test for url
|
||||
onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(2).perform(click());
|
||||
intended(expectedIntent);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() {
|
||||
super.afterTest();
|
||||
Intents.release();
|
||||
}
|
||||
|
||||
private void buildUrlSpans() {
|
||||
onView(withId(R.id.mapView)).perform(new MapLibreMapAction((uiController, view) -> {
|
||||
for (Source source : maplibreMap.getStyle().getSources()) {
|
||||
String attributionSource = source.getAttribution();
|
||||
if (!TextUtils.isEmpty(attributionSource)) {
|
||||
SpannableStringBuilder htmlBuilder = (SpannableStringBuilder) Html.fromHtml(attributionSource);
|
||||
urlSpans = htmlBuilder.getSpans(0, htmlBuilder.length(), URLSpan.class);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private class DisableAction implements ViewAction {
|
||||
|
||||
private MapLibreMap maplibreMap;
|
||||
|
||||
DisableAction(MapLibreMap map) {
|
||||
maplibreMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
maplibreMap.getUiSettings().setAttributionEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class MapLibreMapAction implements ViewAction {
|
||||
|
||||
private InvokeViewAction invokeViewAction;
|
||||
|
||||
MapLibreMapAction(InvokeViewAction invokeViewAction) {
|
||||
this.invokeViewAction = invokeViewAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
invokeViewAction.onViewAction(uiController, view);
|
||||
}
|
||||
}
|
||||
|
||||
interface InvokeViewAction {
|
||||
void onViewAction(UiController uiController, View view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.maplibre.android.testapp.maps.widgets;
|
||||
|
||||
import org.maplibre.android.camera.CameraPosition;
|
||||
import org.maplibre.android.camera.CameraUpdateFactory;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.testapp.action.WaitAction;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.TestConstants;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class CompassViewTest extends EspressoTest {
|
||||
|
||||
@Test
|
||||
public void testDefault() {
|
||||
validateTestSetup();
|
||||
onView(withTagValue(is("compassView"))).check(matches(not(isDisplayed())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("No explanation given")
|
||||
public void testVisible() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
|
||||
new CameraPosition.Builder()
|
||||
.bearing(45)
|
||||
.zoom(1)
|
||||
.target(new LatLng())
|
||||
.build()
|
||||
));
|
||||
uiController.loopMainThreadForAtLeast(500);
|
||||
});
|
||||
onView(withTagValue(is("compassView"))).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("No explanation given")
|
||||
public void testClick() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
|
||||
new CameraPosition.Builder()
|
||||
.bearing(45)
|
||||
.zoom(1)
|
||||
.target(new LatLng())
|
||||
.build()
|
||||
)));
|
||||
onView(withTagValue(is("compassView"))).perform(click());
|
||||
WaitAction.invoke(500);
|
||||
onView(withTagValue(is("compassView"))).check(matches(not(isDisplayed())));
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
|
||||
assertEquals("Camera bearing should face north, ", 0, cameraPosition.bearing, TestConstants.BEARING_DELTA);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.maplibre.android.testapp.maps.widgets;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
|
||||
import org.maplibre.android.maps.MapLibreMap;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Test;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
public class LogoTest extends EspressoTest {
|
||||
|
||||
@Test
|
||||
public void testDefault() {
|
||||
validateTestSetup();
|
||||
onView(withTagValue(is("logoView"))).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisabled() {
|
||||
validateTestSetup();
|
||||
|
||||
onView(withTagValue(is("logoView")))
|
||||
.perform(new DisableAction(maplibreMap))
|
||||
.check(matches(not(isDisplayed())));
|
||||
}
|
||||
|
||||
private class DisableAction implements ViewAction {
|
||||
|
||||
private MapLibreMap maplibreMap;
|
||||
|
||||
DisableAction(MapLibreMap map) {
|
||||
maplibreMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
maplibreMap.getUiSettings().setLogoEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.maplibre.android.testapp.offline
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.offline.OfflineManager
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class CacheTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
private val context: Context by lazy { rule.activity }
|
||||
|
||||
private val countDownLatch = CountDownLatch(1)
|
||||
|
||||
@Test
|
||||
fun testSetMaximumAmbientCacheSize() {
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).setMaximumAmbientCacheSize(
|
||||
10000000,
|
||||
object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertNull("onError should not be called", message)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
countDownLatch.await()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetClearAmbientCache() {
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).clearAmbientCache(object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertNull("onError should not be called", message)
|
||||
}
|
||||
})
|
||||
}
|
||||
countDownLatch.await()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetInvalidateAmbientCache() {
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertNull("onError should not be called", message)
|
||||
}
|
||||
})
|
||||
}
|
||||
countDownLatch.await()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetResetDatabase() {
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).resetDatabase(object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertNull("onError should not be called", message)
|
||||
}
|
||||
})
|
||||
}
|
||||
countDownLatch.await()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetPackDatabase() {
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).packDatabase(object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertNull("onError should not be called", message)
|
||||
}
|
||||
})
|
||||
}
|
||||
countDownLatch.await()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package org.maplibre.android.testapp.offline
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.offline.OfflineManager
|
||||
import org.maplibre.android.offline.OfflineRegion
|
||||
import org.maplibre.android.storage.FileSource
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.maplibre.android.testapp.utils.FileUtils
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class OfflineManagerTest : AppCenter() {
|
||||
|
||||
companion object {
|
||||
private const val TEST_DB_FILE_NAME = "offline_test.db"
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
private val context: Context by lazy { rule.activity }
|
||||
|
||||
@Before
|
||||
@After
|
||||
fun resetDatabase() {
|
||||
val latch = CountDownLatch(1)
|
||||
OfflineManager.getInstance(context).resetDatabase(object : OfflineManager.FileSourceCallback {
|
||||
override fun onSuccess() {
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
throw IOException("Unable to reset database before / after tests.")
|
||||
}
|
||||
})
|
||||
latch.await()
|
||||
}
|
||||
|
||||
@Test(timeout = 30_000)
|
||||
fun combinedTest() {
|
||||
|
||||
lateinit var mergedRegion: OfflineRegion
|
||||
|
||||
// Copy file from assets
|
||||
|
||||
val latch1 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
FileUtils.CopyFileFromAssetsTask(
|
||||
rule.activity,
|
||||
object : FileUtils.OnFileCopiedFromAssetsListener {
|
||||
override fun onFileCopiedFromAssets() {
|
||||
latch1.countDown()
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
throw IOException("Unable to copy DB file.")
|
||||
}
|
||||
}
|
||||
).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity))
|
||||
}
|
||||
latch1.await()
|
||||
|
||||
// Merge a second region
|
||||
|
||||
val latch2 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).mergeOfflineRegions(
|
||||
FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME,
|
||||
object : OfflineManager.MergeOfflineRegionsCallback {
|
||||
override fun onMerge(offlineRegions: Array<OfflineRegion>?) {
|
||||
Assert.assertEquals(1, offlineRegions?.size)
|
||||
latch2.countDown()
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
throw RuntimeException("Unable to merge external offline database. $error")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
latch2.await()
|
||||
|
||||
// List regions (ensure merge yielded one region only)
|
||||
|
||||
val latch3 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
||||
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
||||
Assert.assertEquals(1, offlineRegions?.size)
|
||||
mergedRegion = offlineRegions!![0]
|
||||
latch3.countDown()
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
throw RuntimeException("Unable to list regions in offline database. $error")
|
||||
}
|
||||
})
|
||||
}
|
||||
latch3.await()
|
||||
|
||||
// Invalidate region
|
||||
|
||||
val latch4 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
mergedRegion.invalidate(object : OfflineRegion.OfflineRegionInvalidateCallback {
|
||||
override fun onInvalidate() {
|
||||
latch4.countDown()
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
throw RuntimeException("Unable to invalidate region")
|
||||
}
|
||||
})
|
||||
}
|
||||
latch4.await()
|
||||
|
||||
// Delete region
|
||||
|
||||
val latch5 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
|
||||
override fun onDelete() {
|
||||
latch5.countDown()
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
throw RuntimeException("Unable to delete region")
|
||||
}
|
||||
})
|
||||
}
|
||||
latch5.await()
|
||||
|
||||
// List regions (ensure deletion was successful)
|
||||
|
||||
val latch6 = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
||||
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
||||
Assert.assertEquals(0, offlineRegions?.size)
|
||||
latch6.countDown()
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
throw RuntimeException("Unable to list regions in offline database. $error")
|
||||
}
|
||||
})
|
||||
}
|
||||
latch6.await()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.maplibre.android.testapp.offline
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.testapp.activity.offline.OfflineActivity
|
||||
import org.maplibre.android.testapp.utils.OfflineUtils.convertRegionName
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.util.*
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class OfflineUtilsTest : AppCenter() {
|
||||
@Test
|
||||
@Throws(UnsupportedEncodingException::class)
|
||||
fun testOfflineUtilsConvertToBytes() {
|
||||
val expected = CONVERTED_REGION_NAME.toByteArray(OfflineActivity.JSON_CHARSET)
|
||||
val actual = convertRegionName(REGION_NAME)
|
||||
Assert.assertTrue("Bytes arrays should match", Arrays.equals(expected, actual))
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(UnsupportedEncodingException::class)
|
||||
fun testOfflineUtilsConvertToString() {
|
||||
val actual =
|
||||
convertRegionName(CONVERTED_REGION_NAME.toByteArray(OfflineActivity.JSON_CHARSET))
|
||||
Assert.assertEquals("Strings should match", REGION_NAME, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOfflineUtilsConvertNoOp() {
|
||||
val convertNoOp = convertRegionName(convertRegionName(REGION_NAME)!!)
|
||||
Assert.assertEquals("Strings should match", REGION_NAME, convertNoOp)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REGION_NAME = "hello world"
|
||||
private const val CONVERTED_REGION_NAME = "{\"FIELD_REGION_NAME\":\"hello world\"}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.maplibre.android.testapp.render;
|
||||
|
||||
import android.Manifest;
|
||||
|
||||
import androidx.test.espresso.IdlingPolicies;
|
||||
import androidx.test.espresso.IdlingRegistry;
|
||||
import androidx.test.espresso.IdlingResourceTimeoutException;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
|
||||
import org.maplibre.android.AppCenter;
|
||||
import org.maplibre.android.testapp.activity.render.RenderTestActivity;
|
||||
import org.maplibre.android.testapp.utils.SnapshotterIdlingResource;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
|
||||
/**
|
||||
* Instrumentation render tests
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class RenderTest extends AppCenter {
|
||||
|
||||
private static final int RENDER_TEST_TIMEOUT = 30;
|
||||
private SnapshotterIdlingResource idlingResource;
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<RenderTestActivity> activityRule = new ActivityTestRule<>(RenderTestActivity.class);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule writeRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule readRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
IdlingPolicies.setMasterPolicyTimeout(RENDER_TEST_TIMEOUT, TimeUnit.MINUTES);
|
||||
setupIdlingResource();
|
||||
}
|
||||
|
||||
private void setupIdlingResource() {
|
||||
try {
|
||||
Timber.e("@Before test: register idle resource");
|
||||
IdlingPolicies.setIdlingResourceTimeout(RENDER_TEST_TIMEOUT, TimeUnit.MINUTES);
|
||||
IdlingRegistry.getInstance().register(idlingResource = new SnapshotterIdlingResource(activityRule.getActivity()));
|
||||
} catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
|
||||
throw new RuntimeException("Idling out!");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testRender() {
|
||||
onView(withId(android.R.id.content)).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() {
|
||||
Timber.e("@After test: unregister idle resource");
|
||||
IdlingRegistry.getInstance().unregister(idlingResource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.maplibre.android.testapp.storage
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.storage.FileSource
|
||||
import org.maplibre.android.testapp.activity.espresso.EspressoTestActivity
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestName
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
open class FileSourceMapTest : AppCenter() {
|
||||
|
||||
private lateinit var fileSourceTestUtils: FileSourceTestUtils
|
||||
|
||||
@get:Rule
|
||||
val rule = ActivityTestRule(EspressoTestActivity::class.java)
|
||||
|
||||
@get:Rule
|
||||
val testName = TestName()
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
fun setup() {
|
||||
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
|
||||
fileSourceTestUtils.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun changeResourcesPathWhileMapVisible() {
|
||||
val latch = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
FileSource.setResourcesCachePath(
|
||||
fileSourceTestUtils.testPath,
|
||||
object : FileSource.ResourcesCachePathChangeCallback {
|
||||
override fun onSuccess(path: String) {
|
||||
latch.countDown()
|
||||
Assert.assertEquals(fileSourceTestUtils.testPath, path)
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.fail("Resources path can be changed while the map is running")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
latch.await()
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanup() {
|
||||
fileSourceTestUtils.cleanup()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.maplibre.android.testapp.storage
|
||||
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.storage.FileSource
|
||||
import org.maplibre.android.testapp.activity.FeatureOverviewActivity
|
||||
import org.junit.*
|
||||
import org.junit.rules.TestName
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class FileSourceStandaloneTest : AppCenter() {
|
||||
|
||||
private lateinit var fileSourceTestUtils: FileSourceTestUtils
|
||||
private lateinit var fileSource: FileSource
|
||||
|
||||
@get:Rule
|
||||
val rule = ActivityTestRule(FeatureOverviewActivity::class.java)
|
||||
|
||||
@get:Rule
|
||||
val testName = TestName()
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
fun setup() {
|
||||
fileSource = FileSource.getInstance(rule.activity)
|
||||
fileSourceTestUtils = FileSourceTestUtils(rule.activity)
|
||||
fileSourceTestUtils.setup()
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testDefault() {
|
||||
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testActivateDeactivate() {
|
||||
Assert.assertTrue("1) FileSource should be active", fileSource.isActivated)
|
||||
fileSource.deactivate()
|
||||
Assert.assertFalse("2) FileSource should not be active", fileSource.isActivated)
|
||||
fileSource.activate()
|
||||
Assert.assertTrue("3) FileSource should be active", fileSource.isActivated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pathChangeTest() {
|
||||
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
|
||||
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
|
||||
|
||||
fileSourceTestUtils.changePath(fileSourceTestUtils.testPath)
|
||||
Assert.assertEquals(fileSourceTestUtils.testPath, FileSource.getResourcesCachePath(rule.activity))
|
||||
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
|
||||
|
||||
fileSourceTestUtils.changePath(fileSourceTestUtils.originalPath)
|
||||
Assert.assertEquals(fileSourceTestUtils.originalPath, FileSource.getResourcesCachePath(rule.activity))
|
||||
Assert.assertTrue("FileSource should be active", fileSource.isActivated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun overridePathChangeCallTest() {
|
||||
val firstLatch = CountDownLatch(1)
|
||||
val secondLatch = CountDownLatch(1)
|
||||
rule.activity.runOnUiThread {
|
||||
FileSource.setResourcesCachePath(
|
||||
fileSourceTestUtils.testPath,
|
||||
object : FileSource.ResourcesCachePathChangeCallback {
|
||||
override fun onSuccess(path: String) {
|
||||
Assert.assertEquals(fileSourceTestUtils.testPath, path)
|
||||
firstLatch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.fail("First attempt should succeed.")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
FileSource.setResourcesCachePath(
|
||||
fileSourceTestUtils.testPath2,
|
||||
object : FileSource.ResourcesCachePathChangeCallback {
|
||||
override fun onSuccess(path: String) {
|
||||
Assert.fail("Second attempt should fail because first one is in progress.")
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.assertEquals("Another resources cache path change is in progress", message)
|
||||
secondLatch.countDown()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (!secondLatch.await(5, TimeUnit.SECONDS)) {
|
||||
Assert.fail("Second attempt should fail.")
|
||||
}
|
||||
|
||||
if (!firstLatch.await(5, TimeUnit.SECONDS)) {
|
||||
Assert.fail("First attempt should succeed.")
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanup() {
|
||||
fileSourceTestUtils.cleanup()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.maplibre.android.testapp.storage
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.maplibre.android.AppCenter
|
||||
import org.maplibre.android.storage.FileSource
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
class FileSourceTestUtils(private val activity: Activity) : AppCenter() {
|
||||
val originalPath = FileSource.getResourcesCachePath(activity)
|
||||
val testPath = "$originalPath/test"
|
||||
val testPath2 = "$originalPath/test2"
|
||||
|
||||
private val paths = listOf(testPath, testPath2)
|
||||
|
||||
fun setup() {
|
||||
for (path in paths) {
|
||||
val testFile = File(path)
|
||||
testFile.mkdirs()
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun cleanup() {
|
||||
val currentPath = FileSource.getResourcesCachePath(activity)
|
||||
if (currentPath != originalPath) {
|
||||
changePath(originalPath)
|
||||
}
|
||||
|
||||
for (path in paths) {
|
||||
val testFile = File(path)
|
||||
if (testFile.exists()) {
|
||||
testFile.deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun changePath(requestedPath: String) {
|
||||
val latch = CountDownLatch(1)
|
||||
activity.runOnUiThread {
|
||||
FileSource.setResourcesCachePath(
|
||||
requestedPath,
|
||||
object : FileSource.ResourcesCachePathChangeCallback {
|
||||
override fun onSuccess(path: String) {
|
||||
Assert.assertEquals(requestedPath, path)
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
override fun onError(message: String) {
|
||||
Assert.fail("Resource path change failed - path: $requestedPath, message: $message")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
latch.await()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.maplibre.android.testapp.string;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test verifying if String#toUpperCase and String#toLowerCase produces desired results
|
||||
* <p>
|
||||
* See core test in https://github.com/mapbox/mapbox-gl-native/blob/master/test/util/text_conversions.test.cpp
|
||||
* </p>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class UppperLowerCaseTest extends EspressoTest {
|
||||
|
||||
@Test
|
||||
public void testToUpperCase() {
|
||||
assertEquals("STREET", "strEEt".toUpperCase()); // EN
|
||||
assertEquals("ROAD", "rOAd".toUpperCase()); // EN
|
||||
|
||||
assertEquals("STRASSE", "straße".toUpperCase()); // DE
|
||||
assertEquals("MASSE", "maße".toUpperCase()); // DE
|
||||
assertEquals("WEISSKOPFSEEADLER", "weißkopfseeadler".toUpperCase()); // DE
|
||||
|
||||
assertEquals("BÊNÇÃO", "bênção".toUpperCase()); // PT
|
||||
assertEquals("AZƏRBAYCAN", "Azərbaycan".toUpperCase()); // AZ
|
||||
assertEquals("ὈΔΥΣΣΕΎΣ", "Ὀδυσσεύς".toUpperCase()); // GR
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToLowerCase() {
|
||||
assertEquals("street", "strEEt".toLowerCase()); // EN
|
||||
assertEquals("road", "rOAd".toLowerCase()); // EN
|
||||
|
||||
assertEquals("straße", "Straße".toLowerCase()); // DE
|
||||
assertEquals("strasse", "STRASSE".toLowerCase()); // DE
|
||||
assertEquals("masse", "MASSE".toLowerCase()); // DE
|
||||
assertEquals("weisskopfseeadler", "weiSSkopfseeadler".toLowerCase()); // DE
|
||||
|
||||
assertEquals("bênção", "BÊNÇÃO".toLowerCase()); // PT
|
||||
assertEquals("azərbaycan", "AZƏRBAYCAN".toLowerCase()); //
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.BackgroundLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for BackgroundLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class BackgroundLayerTest extends BaseLayerTest {
|
||||
|
||||
private BackgroundLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new BackgroundLayer("my-layer");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundColorTransition() {
|
||||
Timber.i("background-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setBackgroundColorTransition(options);
|
||||
assertEquals(layer.getBackgroundColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundColorAsConstant() {
|
||||
Timber.i("background-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBackgroundColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(backgroundColor(propertyValue));
|
||||
assertEquals(layer.getBackgroundColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundColorAsIntConstant() {
|
||||
Timber.i("background-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(backgroundColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getBackgroundColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundPatternTransition() {
|
||||
Timber.i("background-patternTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setBackgroundPatternTransition(options);
|
||||
assertEquals(layer.getBackgroundPatternTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundPatternAsConstant() {
|
||||
Timber.i("background-pattern");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBackgroundPattern().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "pedestrian-polygon";
|
||||
layer.setProperties(backgroundPattern(propertyValue));
|
||||
assertEquals(layer.getBackgroundPattern().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundOpacityTransition() {
|
||||
Timber.i("background-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setBackgroundOpacityTransition(options);
|
||||
assertEquals(layer.getBackgroundOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testBackgroundOpacityAsConstant() {
|
||||
Timber.i("background-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getBackgroundOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(backgroundOpacity(propertyValue));
|
||||
assertEquals(layer.getBackgroundOpacity().getValue(), propertyValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,555 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.CircleLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for CircleLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class CircleLayerTest extends BaseLayerTest {
|
||||
|
||||
private CircleLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new CircleLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleSortKeyAsConstant() {
|
||||
Timber.i("circle-sort-key");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleSortKey().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleSortKey(propertyValue));
|
||||
assertEquals(layer.getCircleSortKey().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleSortKeyAsExpression() {
|
||||
Timber.i("circle-sort-key-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleSortKey().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleSortKey(expression));
|
||||
assertEquals(layer.getCircleSortKey().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleRadiusTransition() {
|
||||
Timber.i("circle-radiusTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleRadiusTransition(options);
|
||||
assertEquals(layer.getCircleRadiusTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleRadiusAsConstant() {
|
||||
Timber.i("circle-radius");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleRadius().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleRadius(propertyValue));
|
||||
assertEquals(layer.getCircleRadius().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleRadiusAsExpression() {
|
||||
Timber.i("circle-radius-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleRadius().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleRadius(expression));
|
||||
assertEquals(layer.getCircleRadius().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleColorTransition() {
|
||||
Timber.i("circle-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleColorTransition(options);
|
||||
assertEquals(layer.getCircleColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleColorAsConstant() {
|
||||
Timber.i("circle-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(circleColor(propertyValue));
|
||||
assertEquals(layer.getCircleColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleColorAsExpression() {
|
||||
Timber.i("circle-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(circleColor(expression));
|
||||
assertEquals(layer.getCircleColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleColorAsIntConstant() {
|
||||
Timber.i("circle-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(circleColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getCircleColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleBlurTransition() {
|
||||
Timber.i("circle-blurTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleBlurTransition(options);
|
||||
assertEquals(layer.getCircleBlurTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleBlurAsConstant() {
|
||||
Timber.i("circle-blur");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleBlur().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleBlur(propertyValue));
|
||||
assertEquals(layer.getCircleBlur().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleBlurAsExpression() {
|
||||
Timber.i("circle-blur-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleBlur().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleBlur(expression));
|
||||
assertEquals(layer.getCircleBlur().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleOpacityTransition() {
|
||||
Timber.i("circle-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleOpacityTransition(options);
|
||||
assertEquals(layer.getCircleOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleOpacityAsConstant() {
|
||||
Timber.i("circle-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleOpacity(propertyValue));
|
||||
assertEquals(layer.getCircleOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleOpacityAsExpression() {
|
||||
Timber.i("circle-opacity-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleOpacity().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleOpacity(expression));
|
||||
assertEquals(layer.getCircleOpacity().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleTranslateTransition() {
|
||||
Timber.i("circle-translateTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleTranslateTransition(options);
|
||||
assertEquals(layer.getCircleTranslateTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleTranslateAsConstant() {
|
||||
Timber.i("circle-translate");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleTranslate().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float[] propertyValue = new Float[] {0f, 0f};
|
||||
layer.setProperties(circleTranslate(propertyValue));
|
||||
assertEquals(layer.getCircleTranslate().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleTranslateAnchorAsConstant() {
|
||||
Timber.i("circle-translate-anchor");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleTranslateAnchor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = CIRCLE_TRANSLATE_ANCHOR_MAP;
|
||||
layer.setProperties(circleTranslateAnchor(propertyValue));
|
||||
assertEquals(layer.getCircleTranslateAnchor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCirclePitchScaleAsConstant() {
|
||||
Timber.i("circle-pitch-scale");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCirclePitchScale().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = CIRCLE_PITCH_SCALE_MAP;
|
||||
layer.setProperties(circlePitchScale(propertyValue));
|
||||
assertEquals(layer.getCirclePitchScale().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCirclePitchAlignmentAsConstant() {
|
||||
Timber.i("circle-pitch-alignment");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCirclePitchAlignment().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = CIRCLE_PITCH_ALIGNMENT_MAP;
|
||||
layer.setProperties(circlePitchAlignment(propertyValue));
|
||||
assertEquals(layer.getCirclePitchAlignment().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeWidthTransition() {
|
||||
Timber.i("circle-stroke-widthTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleStrokeWidthTransition(options);
|
||||
assertEquals(layer.getCircleStrokeWidthTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeWidthAsConstant() {
|
||||
Timber.i("circle-stroke-width");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeWidth().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleStrokeWidth(propertyValue));
|
||||
assertEquals(layer.getCircleStrokeWidth().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeWidthAsExpression() {
|
||||
Timber.i("circle-stroke-width-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeWidth().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleStrokeWidth(expression));
|
||||
assertEquals(layer.getCircleStrokeWidth().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeColorTransition() {
|
||||
Timber.i("circle-stroke-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleStrokeColorTransition(options);
|
||||
assertEquals(layer.getCircleStrokeColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeColorAsConstant() {
|
||||
Timber.i("circle-stroke-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(circleStrokeColor(propertyValue));
|
||||
assertEquals(layer.getCircleStrokeColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeColorAsExpression() {
|
||||
Timber.i("circle-stroke-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(circleStrokeColor(expression));
|
||||
assertEquals(layer.getCircleStrokeColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeColorAsIntConstant() {
|
||||
Timber.i("circle-stroke-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(circleStrokeColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getCircleStrokeColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeOpacityTransition() {
|
||||
Timber.i("circle-stroke-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setCircleStrokeOpacityTransition(options);
|
||||
assertEquals(layer.getCircleStrokeOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeOpacityAsConstant() {
|
||||
Timber.i("circle-stroke-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(circleStrokeOpacity(propertyValue));
|
||||
assertEquals(layer.getCircleStrokeOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testCircleStrokeOpacityAsExpression() {
|
||||
Timber.i("circle-stroke-opacity-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getCircleStrokeOpacity().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(circleStrokeOpacity(expression));
|
||||
assertEquals(layer.getCircleStrokeOpacity().getExpression(), expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.maplibre.android.testapp.style
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
import org.maplibre.android.style.sources.CustomGeometrySource.Companion.THREAD_POOL_LIMIT
|
||||
import org.maplibre.android.style.sources.CustomGeometrySource.Companion.THREAD_PREFIX
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction.invoke
|
||||
import org.maplibre.android.testapp.action.OrientationAction.orientationLandscape
|
||||
import org.maplibre.android.testapp.action.OrientationAction.orientationPortrait
|
||||
import org.maplibre.android.testapp.action.WaitAction
|
||||
import org.maplibre.android.testapp.activity.BaseTest
|
||||
import org.maplibre.android.testapp.activity.style.GridSourceActivity
|
||||
import org.maplibre.android.testapp.activity.style.GridSourceActivity.Companion.ID_GRID_LAYER
|
||||
import org.maplibre.android.testapp.activity.style.GridSourceActivity.Companion.ID_GRID_SOURCE
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
|
||||
class CustomGeometrySourceTest : BaseTest() {
|
||||
|
||||
override fun getActivityClass(): Class<*> = GridSourceActivity::class.java
|
||||
|
||||
@Test
|
||||
fun sourceNotLeakingThreadsTest() {
|
||||
validateTestSetup()
|
||||
WaitAction.invoke(4000)
|
||||
onView(isRoot()).perform(orientationLandscape())
|
||||
WaitAction.invoke(2000)
|
||||
onView(isRoot()).perform(orientationPortrait())
|
||||
WaitAction.invoke(2000)
|
||||
Assert.assertFalse(
|
||||
"Threads should be shutdown when the source is destroyed.",
|
||||
Thread.getAllStackTraces().keys.filter {
|
||||
it.name.startsWith(THREAD_PREFIX)
|
||||
}.count() > THREAD_POOL_LIMIT
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun threadsShutdownWhenSourceRemovedTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
mapboxMap.style!!.removeLayer(ID_GRID_LAYER)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
Assert.assertTrue(
|
||||
"There should be no threads running when the source is removed.",
|
||||
Thread.getAllStackTraces().keys.filter {
|
||||
it.name.startsWith(THREAD_PREFIX)
|
||||
}.count() == 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun threadsRestartedWhenSourceReAddedTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer!!)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source!!)
|
||||
mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer!!)
|
||||
TestingAsyncUtils.waitForLayer(uiController, mapView)
|
||||
Assert.assertTrue(
|
||||
"Threads should be restarted when the source is re-added to the map.",
|
||||
Thread.getAllStackTraces().keys.filter {
|
||||
it.name.startsWith(THREAD_PREFIX)
|
||||
}.count() == THREAD_POOL_LIMIT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sourceZoomDeltaTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
mapboxMap.prefetchZoomDelta = 3
|
||||
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
|
||||
assertNull(it.prefetchZoomDelta)
|
||||
it.prefetchZoomDelta = 5
|
||||
assertNotNull(it.prefetchZoomDelta)
|
||||
assertEquals(5, it.prefetchZoomDelta!!)
|
||||
it.prefetchZoomDelta = null
|
||||
assertNull(it.prefetchZoomDelta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isVolatileTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
|
||||
assertFalse(it.isVolatile)
|
||||
it.isVolatile = true
|
||||
assertTrue(it.isVolatile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun minimumTileUpdateIntervalTest() {
|
||||
validateTestSetup()
|
||||
invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
mapboxMap.style!!.getSource(ID_GRID_SOURCE)!!.let {
|
||||
assertEquals(0, it.minimumTileUpdateInterval)
|
||||
it.minimumTileUpdateInterval = 1000
|
||||
assertEquals(1000, it.minimumTileUpdateInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,784 @@
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.geojson.Point;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.CircleLayer;
|
||||
import org.maplibre.android.style.layers.FillLayer;
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.style.layers.SymbolLayer;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
import org.maplibre.android.style.sources.Source;
|
||||
import org.maplibre.android.style.types.Formatted;
|
||||
import org.maplibre.android.style.types.FormattedSection;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.ResourceUtils;
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils;
|
||||
import org.maplibre.android.utils.ColorUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.FormatOption.formatFontScale;
|
||||
import static org.maplibre.android.style.expressions.Expression.FormatOption.formatTextColor;
|
||||
import static org.maplibre.android.style.expressions.Expression.FormatOption.formatTextFont;
|
||||
import static org.maplibre.android.style.expressions.Expression.NumberFormatOption.currency;
|
||||
import static org.maplibre.android.style.expressions.Expression.NumberFormatOption.locale;
|
||||
import static org.maplibre.android.style.expressions.Expression.NumberFormatOption.maxFractionDigits;
|
||||
import static org.maplibre.android.style.expressions.Expression.NumberFormatOption.minFractionDigits;
|
||||
import static org.maplibre.android.style.expressions.Expression.collator;
|
||||
import static org.maplibre.android.style.expressions.Expression.color;
|
||||
import static org.maplibre.android.style.expressions.Expression.eq;
|
||||
import static org.maplibre.android.style.expressions.Expression.exponential;
|
||||
import static org.maplibre.android.style.expressions.Expression.format;
|
||||
import static org.maplibre.android.style.expressions.Expression.formatEntry;
|
||||
import static org.maplibre.android.style.expressions.Expression.get;
|
||||
import static org.maplibre.android.style.expressions.Expression.interpolate;
|
||||
import static org.maplibre.android.style.expressions.Expression.literal;
|
||||
import static org.maplibre.android.style.expressions.Expression.match;
|
||||
import static org.maplibre.android.style.expressions.Expression.number;
|
||||
import static org.maplibre.android.style.expressions.Expression.numberFormat;
|
||||
import static org.maplibre.android.style.expressions.Expression.rgb;
|
||||
import static org.maplibre.android.style.expressions.Expression.rgba;
|
||||
import static org.maplibre.android.style.expressions.Expression.step;
|
||||
import static org.maplibre.android.style.expressions.Expression.stop;
|
||||
import static org.maplibre.android.style.expressions.Expression.string;
|
||||
import static org.maplibre.android.style.expressions.Expression.switchCase;
|
||||
import static org.maplibre.android.style.expressions.Expression.toColor;
|
||||
import static org.maplibre.android.style.expressions.Expression.zoom;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.circleColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillAntialias;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillOutlineColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.textColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.textField;
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class ExpressionTest extends EspressoTest {
|
||||
private FillLayer layer;
|
||||
|
||||
@Test
|
||||
public void testConstantExpressionConversion() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
Timber.i("camera function");
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// create color expression
|
||||
Expression inputExpression = rgba(255.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// set color expression
|
||||
layer.setProperties(
|
||||
fillColor(inputExpression)
|
||||
);
|
||||
|
||||
// get color value
|
||||
int color = layer.getFillColor().getColorInt();
|
||||
|
||||
// compare
|
||||
assertEquals("input expression should match", Color.RED, color);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExpressionWrapping() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
Timber.i("camera function");
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// create get expression
|
||||
Expression inputExpression = get("fill");
|
||||
|
||||
// set get expression
|
||||
layer.setProperties(
|
||||
fillColor(inputExpression)
|
||||
);
|
||||
|
||||
// get actual expression
|
||||
Expression actualExpression = layer.getFillColor().getExpression();
|
||||
|
||||
// create wrapped expected expression
|
||||
Expression expectedExpression = toColor(get("fill"));
|
||||
|
||||
// compare
|
||||
assertEquals("input expression should match", expectedExpression, actualExpression);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCameraFunction() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
Timber.i("camera function");
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// create camera function expression
|
||||
Expression inputExpression = interpolate(
|
||||
exponential(0.5f), zoom(),
|
||||
stop(1.0f, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
|
||||
stop(5.0f, rgba(0.0f, 0.0f, 255.0f, 1.0f)),
|
||||
stop(10.0f, rgba(0.0f, 255.0f, 0.0f, 1.0f))
|
||||
);
|
||||
|
||||
// set camera function expression
|
||||
layer.setProperties(
|
||||
fillColor(inputExpression)
|
||||
);
|
||||
|
||||
// get camera function expression
|
||||
Expression outputExpression = layer.getFillColor().getExpression();
|
||||
|
||||
// compare
|
||||
assertEquals("input expression should match", inputExpression, outputExpression);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSourceFunction() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
Timber.i("camera function");
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// create camera function expression
|
||||
Expression inputExpression = toColor(get("fill"));
|
||||
|
||||
// set camera function expression
|
||||
layer.setProperties(
|
||||
fillColor(inputExpression)
|
||||
);
|
||||
|
||||
// get camera function expression
|
||||
Expression outputExpression = layer.getFillColor().getExpression();
|
||||
|
||||
// compare
|
||||
assertEquals("input expression should match", inputExpression, outputExpression);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompositeFunction() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
Timber.i("camera function");
|
||||
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// create camera function expression
|
||||
Expression inputExpression = step(zoom(),
|
||||
rgba(255.0f, 255.0f, 255.0f, 1.0f),
|
||||
stop(7.0f, match(
|
||||
string(get("name")),
|
||||
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
|
||||
rgba(255.0f, 255.0f, 255.0f, 1.0f)
|
||||
)),
|
||||
stop(8.0f, match(
|
||||
string(get("name")),
|
||||
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
|
||||
rgba(255.0f, 255.0f, 255.0f, 1.0f)
|
||||
))
|
||||
);
|
||||
|
||||
// set camera function expression
|
||||
layer.setProperties(
|
||||
fillColor(inputExpression)
|
||||
);
|
||||
|
||||
// get camera function expression
|
||||
Expression outputExpression = layer.getFillColor().getExpression();
|
||||
|
||||
// compare
|
||||
assertEquals("input expression should match", inputExpression, outputExpression);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiteralProperty() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
layer.setProperties(
|
||||
fillColor(literal("#4286f4"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiteralMatchExpression() {
|
||||
validateTestSetup();
|
||||
setupStyle();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
Expression expression = match(literal("something"), literal(0f),
|
||||
stop("1", get("1")),
|
||||
stop("2", get("2")),
|
||||
stop("3", get("3")),
|
||||
stop("4", get("4"))
|
||||
);
|
||||
|
||||
layer.setProperties(
|
||||
fillColor(expression)
|
||||
);
|
||||
expression.toArray();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollatorExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
|
||||
Expression expression1 = eq(literal("Łukasz"), literal("lukasz"), collator(true, true));
|
||||
Expression expression2 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(1),
|
||||
literal(1)), literal("en")));
|
||||
Expression expression3 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(2),
|
||||
literal(1))));
|
||||
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
Layer layer = new CircleLayer("layer", "source")
|
||||
.withProperties(circleColor(
|
||||
switchCase(
|
||||
expression1, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
|
||||
literal(ColorUtils.colorToRgbaString(Color.RED))
|
||||
)
|
||||
));
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
|
||||
layer.setProperties(circleColor(
|
||||
switchCase(
|
||||
expression2, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
|
||||
literal(ColorUtils.colorToRgbaString(Color.RED))
|
||||
)
|
||||
));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
|
||||
layer.setProperties(circleColor(
|
||||
switchCase(
|
||||
expression3, literal(ColorUtils.colorToRgbaString(Color.GREEN)),
|
||||
literal(ColorUtils.colorToRgbaString(Color.RED))
|
||||
)
|
||||
));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry("test")
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(new FormattedSection("test")), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpressionFontScaleParam() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry("test", formatFontScale(1.75))
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(new FormattedSection("test", 1.75)), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpressionTextFontParam() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
literal("test"),
|
||||
formatTextFont(new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"})
|
||||
)
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(
|
||||
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(
|
||||
new FormattedSection("test",
|
||||
new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"})
|
||||
), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpressionTextColorParam() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
literal("test"),
|
||||
formatTextColor(literal("yellow"))
|
||||
)
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(
|
||||
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(
|
||||
new FormattedSection("test", null, null, "rgba(255,255,0,1)")
|
||||
), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpressionAllParams() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
"test",
|
||||
formatFontScale(0.5),
|
||||
formatTextFont(new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"}),
|
||||
formatTextColor(rgb(126, 0, 0))
|
||||
)
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(
|
||||
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(
|
||||
new FormattedSection("test",
|
||||
0.5,
|
||||
new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"},
|
||||
"rgba(126,0,0,1)")
|
||||
), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstFormatExpressionMultipleInputs() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
"test",
|
||||
formatFontScale(1.5),
|
||||
formatTextFont(new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"})
|
||||
),
|
||||
formatEntry("\ntest2", formatFontScale(2), formatTextColor(Color.BLUE)),
|
||||
formatEntry("\ntest3", formatFontScale(2.5),
|
||||
formatTextColor(toColor(literal("rgba(0, 128, 255, 0.5)"))))
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(
|
||||
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(
|
||||
new FormattedSection("test", 1.5,
|
||||
new String[]{"DIN Offc Pro Regular", "Arial Unicode MS Regular"}),
|
||||
new FormattedSection("\ntest2", 2.0, null, "rgba(0,0,255,1)"),
|
||||
new FormattedSection("\ntest3", 2.5, null, "rgba(0,128,255,0.5)")
|
||||
), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariableFormatExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
|
||||
feature.addStringProperty("test_property", "test");
|
||||
feature.addNumberProperty("test_property_number", 1.5);
|
||||
feature.addStringProperty("test_property_color", "green");
|
||||
mapboxMap.getStyle().addSource(new GeoJsonSource("source", feature));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
get("test_property"),
|
||||
Expression.FormatOption.formatFontScale(number(get("test_property_number"))),
|
||||
formatTextFont(new String[]{"Arial Unicode MS Regular", "DIN Offc Pro Regular"}),
|
||||
formatTextColor(toColor(get("test_property_color")))
|
||||
)
|
||||
);
|
||||
layer.setProperties(textField(expression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertEquals(expression, layer.getTextField().getExpression());
|
||||
assertNull(layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariableFormatExpressionMultipleInputs() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
|
||||
feature.addStringProperty("test_property", "test");
|
||||
feature.addNumberProperty("test_property_number", 1.5);
|
||||
feature.addStringProperty("test_property_color", "rgba(0, 255, 0, 1)");
|
||||
mapboxMap.getStyle().addSource(new GeoJsonSource("source", feature));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression expression = format(
|
||||
formatEntry(
|
||||
get("test_property"),
|
||||
formatFontScale(1.25),
|
||||
formatTextFont(new String[]{"Arial Unicode MS Regular", "DIN Offc Pro Regular"}),
|
||||
formatTextColor(toColor(get("test_property_color")))
|
||||
),
|
||||
formatEntry("\ntest2", formatFontScale(2))
|
||||
);
|
||||
layer.setProperties(textField(expression), textColor("rgba(128, 0, 0, 1)"));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertEquals(expression, layer.getTextField().getExpression());
|
||||
assertNull(layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatExpressionPlainTextCoercion() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
layer.setProperties(textField("test"));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(new Formatted(
|
||||
new FormattedSection("test")), layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextFieldFormattedArgument() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Formatted formatted = new Formatted(
|
||||
new FormattedSection("test", 1.5),
|
||||
new FormattedSection("\ntest", 0.5, new String[]{"Arial Unicode MS Regular",
|
||||
"DIN Offc Pro Regular"}),
|
||||
new FormattedSection("test", null, null, "rgba(0,255,0,1)")
|
||||
);
|
||||
layer.setProperties(textField(formatted), textColor("rgba(128,0,0,1)"));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
|
||||
.isEmpty());
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals(formatted, layer.getTextField().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberFormatCurrencyExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
layer.setProperties(
|
||||
textField(
|
||||
numberFormat(12.345, locale("en-US"), currency("USD"))
|
||||
)
|
||||
);
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals("$12.35", layer.getTextField().getValue().getFormattedSections()[0].getText());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberFormatMaxExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
layer.setProperties(
|
||||
textField(
|
||||
numberFormat(12.34567890, maxFractionDigits(5), minFractionDigits(0))
|
||||
)
|
||||
);
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals("12.34568", layer.getTextField().getValue().getFormattedSections()[0].getText());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberFormatMinExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
layer.setProperties(
|
||||
textField(
|
||||
numberFormat(12.0000001, maxFractionDigits(5), minFractionDigits(0))
|
||||
)
|
||||
);
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals("12", layer.getTextField().getValue().getFormattedSections()[0].getText());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberFormatLocaleExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle()
|
||||
.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
layer.setProperties(
|
||||
textField(
|
||||
numberFormat(12.0000001, locale("nl-BE"), maxFractionDigits(5),
|
||||
minFractionDigits(1))
|
||||
)
|
||||
);
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
assertNull(layer.getTextField().getExpression());
|
||||
assertEquals("12,0", layer.getTextField().getValue().getFormattedSections()[0].getText());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberFormatNonConstantExpression() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
|
||||
feature.addNumberProperty("number_value", 12.345678);
|
||||
feature.addStringProperty("locale_value", "nl-BE");
|
||||
feature.addNumberProperty("max_value", 5);
|
||||
feature.addNumberProperty("min_value", 1);
|
||||
|
||||
|
||||
mapboxMap.getStyle().addSource(new GeoJsonSource("source", feature));
|
||||
SymbolLayer layer = new SymbolLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression numberFormatExpression = numberFormat(
|
||||
number(number(get("number_value"))),
|
||||
locale(string(get("locale_value"))),
|
||||
maxFractionDigits(number(get("max_value"))),
|
||||
minFractionDigits(number(get("min_value")))
|
||||
);
|
||||
|
||||
layer.setProperties(textField(numberFormatExpression));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
|
||||
assertFalse(mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
|
||||
);
|
||||
|
||||
assertNotNull(layer.getTextField().getExpression());
|
||||
|
||||
// Expressions evaluated to string are wrapped by a format expression, take array index 1 to get original
|
||||
Object[] returnExpression = (Object[]) layer.getTextField().getExpression().toArray()[1];
|
||||
Object[] setExpression = numberFormatExpression.toArray();
|
||||
assertEquals("Number format should match", returnExpression[0], setExpression[0]);
|
||||
assertArrayEquals("Get value expression should match",
|
||||
(Object[]) returnExpression[1],
|
||||
(Object[]) setExpression[1]
|
||||
);
|
||||
|
||||
// number format objects
|
||||
HashMap<String, Object> returnMap = (HashMap<String, Object>) returnExpression[2];
|
||||
HashMap<String, Object> setMap = (HashMap<String, Object>) returnExpression[2];
|
||||
|
||||
assertArrayEquals("Number format min fraction digits should match ",
|
||||
(Object[]) returnMap.get("min-fraction-digits"),
|
||||
(Object[]) setMap.get("min-fraction-digits")
|
||||
);
|
||||
|
||||
assertArrayEquals("Number format max fraction digits should match ",
|
||||
(Object[]) returnMap.get("max-fraction-digits"),
|
||||
(Object[]) setMap.get("max-fraction-digits")
|
||||
);
|
||||
|
||||
assertArrayEquals("Number format min fraction digits should match ",
|
||||
(Object[]) returnMap.get("locale"),
|
||||
(Object[]) setMap.get("locale")
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test for #15532
|
||||
*/
|
||||
@Test
|
||||
public void testDoubleConversion() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
LatLng latLng = new LatLng(51, 17);
|
||||
mapboxMap.getStyle().addSource(
|
||||
new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()))
|
||||
);
|
||||
|
||||
CircleLayer layer = new CircleLayer("layer", "source");
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
Expression input = interpolate(
|
||||
exponential(0.5f), zoom(),
|
||||
stop(-0.1, color(Color.RED)),
|
||||
stop(0, color(Color.BLUE))
|
||||
);
|
||||
|
||||
layer.setProperties(circleColor(input));
|
||||
|
||||
Expression output = layer.getCircleColor().getExpression();
|
||||
assertArrayEquals("Expression should match", input.toArray(), output.toArray());
|
||||
});
|
||||
}
|
||||
|
||||
private void setupStyle() {
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
// Add a source
|
||||
Source source;
|
||||
source = new GeoJsonSource("amsterdam-parks-source",
|
||||
ResourceUtils.readRawResource(rule.getActivity(), R.raw.amsterdam));
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
|
||||
// Add a fill layer
|
||||
mapboxMap.getStyle().addLayer(layer = new FillLayer("amsterdam-parks-layer", source.getId())
|
||||
.withProperties(
|
||||
fillColor(rgba(0.0f, 0.0f, 0.0f, 0.5f)),
|
||||
fillOutlineColor(rgb(0, 0, 255)),
|
||||
fillAntialias(true)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.FillExtrusionLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for FillExtrusionLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class FillExtrusionLayerTest extends BaseLayerTest {
|
||||
|
||||
private FillExtrusionLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new FillExtrusionLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionOpacityTransition() {
|
||||
Timber.i("fill-extrusion-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionOpacityTransition(options);
|
||||
assertEquals(layer.getFillExtrusionOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionOpacityAsConstant() {
|
||||
Timber.i("fill-extrusion-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillExtrusionOpacity(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionColorTransition() {
|
||||
Timber.i("fill-extrusion-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionColorTransition(options);
|
||||
assertEquals(layer.getFillExtrusionColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionColorAsConstant() {
|
||||
Timber.i("fill-extrusion-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(fillExtrusionColor(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionColorAsExpression() {
|
||||
Timber.i("fill-extrusion-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(fillExtrusionColor(expression));
|
||||
assertEquals(layer.getFillExtrusionColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionColorAsIntConstant() {
|
||||
Timber.i("fill-extrusion-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(fillExtrusionColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getFillExtrusionColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionTranslateTransition() {
|
||||
Timber.i("fill-extrusion-translateTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionTranslateTransition(options);
|
||||
assertEquals(layer.getFillExtrusionTranslateTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionTranslateAsConstant() {
|
||||
Timber.i("fill-extrusion-translate");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionTranslate().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float[] propertyValue = new Float[] {0f, 0f};
|
||||
layer.setProperties(fillExtrusionTranslate(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionTranslate().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionTranslateAnchorAsConstant() {
|
||||
Timber.i("fill-extrusion-translate-anchor");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionTranslateAnchor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP;
|
||||
layer.setProperties(fillExtrusionTranslateAnchor(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionTranslateAnchor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionPatternTransition() {
|
||||
Timber.i("fill-extrusion-patternTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionPatternTransition(options);
|
||||
assertEquals(layer.getFillExtrusionPatternTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionPatternAsConstant() {
|
||||
Timber.i("fill-extrusion-pattern");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionPattern().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "pedestrian-polygon";
|
||||
layer.setProperties(fillExtrusionPattern(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionPattern().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionPatternAsExpression() {
|
||||
Timber.i("fill-extrusion-pattern-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionPattern().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = image(string(Expression.get("undefined")));
|
||||
layer.setProperties(fillExtrusionPattern(expression));
|
||||
assertEquals(layer.getFillExtrusionPattern().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionHeightTransition() {
|
||||
Timber.i("fill-extrusion-heightTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionHeightTransition(options);
|
||||
assertEquals(layer.getFillExtrusionHeightTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionHeightAsConstant() {
|
||||
Timber.i("fill-extrusion-height");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionHeight().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillExtrusionHeight(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionHeight().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionHeightAsExpression() {
|
||||
Timber.i("fill-extrusion-height-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionHeight().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(fillExtrusionHeight(expression));
|
||||
assertEquals(layer.getFillExtrusionHeight().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionBaseTransition() {
|
||||
Timber.i("fill-extrusion-baseTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillExtrusionBaseTransition(options);
|
||||
assertEquals(layer.getFillExtrusionBaseTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionBaseAsConstant() {
|
||||
Timber.i("fill-extrusion-base");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionBase().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillExtrusionBase(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionBase().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionBaseAsExpression() {
|
||||
Timber.i("fill-extrusion-base-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionBase().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(fillExtrusionBase(expression));
|
||||
assertEquals(layer.getFillExtrusionBase().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillExtrusionVerticalGradientAsConstant() {
|
||||
Timber.i("fill-extrusion-vertical-gradient");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillExtrusionVerticalGradient().getValue());
|
||||
|
||||
// Set and Get
|
||||
Boolean propertyValue = true;
|
||||
layer.setProperties(fillExtrusionVerticalGradient(propertyValue));
|
||||
assertEquals(layer.getFillExtrusionVerticalGradient().getValue(), propertyValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.FillLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for FillLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class FillLayerTest extends BaseLayerTest {
|
||||
|
||||
private FillLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new FillLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillSortKeyAsConstant() {
|
||||
Timber.i("fill-sort-key");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillSortKey().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillSortKey(propertyValue));
|
||||
assertEquals(layer.getFillSortKey().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillSortKeyAsExpression() {
|
||||
Timber.i("fill-sort-key-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillSortKey().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(fillSortKey(expression));
|
||||
assertEquals(layer.getFillSortKey().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillAntialiasAsConstant() {
|
||||
Timber.i("fill-antialias");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillAntialias().getValue());
|
||||
|
||||
// Set and Get
|
||||
Boolean propertyValue = true;
|
||||
layer.setProperties(fillAntialias(propertyValue));
|
||||
assertEquals(layer.getFillAntialias().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOpacityTransition() {
|
||||
Timber.i("fill-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillOpacityTransition(options);
|
||||
assertEquals(layer.getFillOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOpacityAsConstant() {
|
||||
Timber.i("fill-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(fillOpacity(propertyValue));
|
||||
assertEquals(layer.getFillOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOpacityAsExpression() {
|
||||
Timber.i("fill-opacity-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillOpacity().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(fillOpacity(expression));
|
||||
assertEquals(layer.getFillOpacity().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillColorTransition() {
|
||||
Timber.i("fill-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillColorTransition(options);
|
||||
assertEquals(layer.getFillColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillColorAsConstant() {
|
||||
Timber.i("fill-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(fillColor(propertyValue));
|
||||
assertEquals(layer.getFillColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillColorAsExpression() {
|
||||
Timber.i("fill-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(fillColor(expression));
|
||||
assertEquals(layer.getFillColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillColorAsIntConstant() {
|
||||
Timber.i("fill-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(fillColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getFillColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOutlineColorTransition() {
|
||||
Timber.i("fill-outline-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillOutlineColorTransition(options);
|
||||
assertEquals(layer.getFillOutlineColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOutlineColorAsConstant() {
|
||||
Timber.i("fill-outline-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillOutlineColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(fillOutlineColor(propertyValue));
|
||||
assertEquals(layer.getFillOutlineColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOutlineColorAsExpression() {
|
||||
Timber.i("fill-outline-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillOutlineColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(fillOutlineColor(expression));
|
||||
assertEquals(layer.getFillOutlineColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillOutlineColorAsIntConstant() {
|
||||
Timber.i("fill-outline-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(fillOutlineColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getFillOutlineColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillTranslateTransition() {
|
||||
Timber.i("fill-translateTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillTranslateTransition(options);
|
||||
assertEquals(layer.getFillTranslateTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillTranslateAsConstant() {
|
||||
Timber.i("fill-translate");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillTranslate().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float[] propertyValue = new Float[] {0f, 0f};
|
||||
layer.setProperties(fillTranslate(propertyValue));
|
||||
assertEquals(layer.getFillTranslate().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillTranslateAnchorAsConstant() {
|
||||
Timber.i("fill-translate-anchor");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillTranslateAnchor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = FILL_TRANSLATE_ANCHOR_MAP;
|
||||
layer.setProperties(fillTranslateAnchor(propertyValue));
|
||||
assertEquals(layer.getFillTranslateAnchor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillPatternTransition() {
|
||||
Timber.i("fill-patternTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setFillPatternTransition(options);
|
||||
assertEquals(layer.getFillPatternTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillPatternAsConstant() {
|
||||
Timber.i("fill-pattern");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillPattern().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "pedestrian-polygon";
|
||||
layer.setProperties(fillPattern(propertyValue));
|
||||
assertEquals(layer.getFillPattern().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFillPatternAsExpression() {
|
||||
Timber.i("fill-pattern-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getFillPattern().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = image(string(Expression.get("undefined")));
|
||||
layer.setProperties(fillPattern(expression));
|
||||
assertEquals(layer.getFillPattern().getExpression(), expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.geojson.FeatureCollection;
|
||||
import com.mapbox.geojson.Point;
|
||||
import org.maplibre.android.geometry.LatLng;
|
||||
import org.maplibre.android.style.layers.CircleLayer;
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
import org.maplibre.android.testapp.utils.ResourceUtils;
|
||||
import org.maplibre.android.testapp.utils.TestingAsyncUtils;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.RawRes;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link GeoJsonSource}
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class GeoJsonSourceTests extends EspressoTest {
|
||||
|
||||
@Test
|
||||
public void testFeatureCollection() {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = null;
|
||||
source = new GeoJsonSource("source", FeatureCollection
|
||||
.fromJson(ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_collection)));
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
mapboxMap.getStyle().addLayer(new CircleLayer("layer", source.getId()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointGeometry() {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = new GeoJsonSource("source", Point.fromLngLat(0d, 0d));
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
mapboxMap.getStyle().addLayer(new CircleLayer("layer", source.getId()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeatureProperties() {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = null;
|
||||
source = new GeoJsonSource("source",
|
||||
ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_properties));
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
mapboxMap.getStyle().addLayer(new CircleLayer("layer", source.getId()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCoalescing() {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = new GeoJsonSource("source");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
mapboxMap.getStyle().addLayer(new CircleLayer("layer", source.getId()));
|
||||
|
||||
source.setGeoJson(Point.fromLngLat(0, 0));
|
||||
source.setGeoJson(Point.fromLngLat(-25, -25));
|
||||
source.setGeoJson(ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_properties));
|
||||
|
||||
source.setGeoJson(Point.fromLngLat(20, 55));
|
||||
TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
|
||||
assertEquals(1, mapboxMap.queryRenderedFeatures(
|
||||
mapboxMap.getProjection().toScreenLocation(
|
||||
new LatLng(55, 20)), "layer").size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearCollectionDuringConversion() {
|
||||
// https://github.com/mapbox/mapbox-gl-native/issues/14565
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
for (int j = 0; j < 1000; j++) {
|
||||
List<Feature> features = new ArrayList<>();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
features.add(Feature.fromGeometry(Point.fromLngLat(0, 0)));
|
||||
}
|
||||
mapboxMap.getStyle().addSource(new GeoJsonSource("source" + j, FeatureCollection.fromFeatures(features)));
|
||||
features.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointFeature() {
|
||||
testFeatureFromResource(R.raw.test_point_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineStringFeature() {
|
||||
testFeatureFromResource(R.raw.test_line_string_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPolygonFeature() {
|
||||
testFeatureFromResource(R.raw.test_polygon_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPolygonWithHoleFeature() {
|
||||
testFeatureFromResource(R.raw.test_polygon_with_hole_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPointFeature() {
|
||||
testFeatureFromResource(R.raw.test_multi_point_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiLineStringFeature() {
|
||||
testFeatureFromResource(R.raw.test_multi_line_string_feature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPolygonFeature() {
|
||||
testFeatureFromResource(R.raw.test_multi_polygon_feature);
|
||||
}
|
||||
|
||||
protected void testFeatureFromResource(final @RawRes int resource) {
|
||||
validateTestSetup();
|
||||
MapLibreMapAction.invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = new GeoJsonSource("source");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
Layer layer = new CircleLayer("layer", source.getId());
|
||||
mapboxMap.getStyle().addLayer(layer);
|
||||
|
||||
source.setGeoJson(Feature.fromJson(ResourceUtils.readRawResource(rule.getActivity(), resource)));
|
||||
|
||||
mapboxMap.getStyle().removeLayer(layer);
|
||||
mapboxMap.getStyle().removeSource(source);
|
||||
});
|
||||
}
|
||||
|
||||
public abstract class BaseViewAction implements ViewAction {
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.HeatmapLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for HeatmapLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class HeatmapLayerTest extends BaseLayerTest {
|
||||
|
||||
private HeatmapLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new HeatmapLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapRadiusTransition() {
|
||||
Timber.i("heatmap-radiusTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHeatmapRadiusTransition(options);
|
||||
assertEquals(layer.getHeatmapRadiusTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapRadiusAsConstant() {
|
||||
Timber.i("heatmap-radius");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapRadius().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(heatmapRadius(propertyValue));
|
||||
assertEquals(layer.getHeatmapRadius().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapRadiusAsExpression() {
|
||||
Timber.i("heatmap-radius-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapRadius().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(heatmapRadius(expression));
|
||||
assertEquals(layer.getHeatmapRadius().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapWeightAsConstant() {
|
||||
Timber.i("heatmap-weight");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapWeight().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(heatmapWeight(propertyValue));
|
||||
assertEquals(layer.getHeatmapWeight().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapWeightAsExpression() {
|
||||
Timber.i("heatmap-weight-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapWeight().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(heatmapWeight(expression));
|
||||
assertEquals(layer.getHeatmapWeight().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapIntensityTransition() {
|
||||
Timber.i("heatmap-intensityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHeatmapIntensityTransition(options);
|
||||
assertEquals(layer.getHeatmapIntensityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapIntensityAsConstant() {
|
||||
Timber.i("heatmap-intensity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapIntensity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(heatmapIntensity(propertyValue));
|
||||
assertEquals(layer.getHeatmapIntensity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapOpacityTransition() {
|
||||
Timber.i("heatmap-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHeatmapOpacityTransition(options);
|
||||
assertEquals(layer.getHeatmapOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHeatmapOpacityAsConstant() {
|
||||
Timber.i("heatmap-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHeatmapOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(heatmapOpacity(propertyValue));
|
||||
assertEquals(layer.getHeatmapOpacity().getValue(), propertyValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.HillshadeLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for HillshadeLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class HillshadeLayerTest extends BaseLayerTest {
|
||||
|
||||
private HillshadeLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new HillshadeLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeIlluminationDirectionAsConstant() {
|
||||
Timber.i("hillshade-illumination-direction");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeIlluminationDirection().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(hillshadeIlluminationDirection(propertyValue));
|
||||
assertEquals(layer.getHillshadeIlluminationDirection().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeIlluminationAnchorAsConstant() {
|
||||
Timber.i("hillshade-illumination-anchor");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeIlluminationAnchor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = HILLSHADE_ILLUMINATION_ANCHOR_MAP;
|
||||
layer.setProperties(hillshadeIlluminationAnchor(propertyValue));
|
||||
assertEquals(layer.getHillshadeIlluminationAnchor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeExaggerationTransition() {
|
||||
Timber.i("hillshade-exaggerationTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHillshadeExaggerationTransition(options);
|
||||
assertEquals(layer.getHillshadeExaggerationTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeExaggerationAsConstant() {
|
||||
Timber.i("hillshade-exaggeration");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeExaggeration().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(hillshadeExaggeration(propertyValue));
|
||||
assertEquals(layer.getHillshadeExaggeration().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeShadowColorTransition() {
|
||||
Timber.i("hillshade-shadow-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHillshadeShadowColorTransition(options);
|
||||
assertEquals(layer.getHillshadeShadowColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeShadowColorAsConstant() {
|
||||
Timber.i("hillshade-shadow-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeShadowColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(hillshadeShadowColor(propertyValue));
|
||||
assertEquals(layer.getHillshadeShadowColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeShadowColorAsIntConstant() {
|
||||
Timber.i("hillshade-shadow-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(hillshadeShadowColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getHillshadeShadowColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeHighlightColorTransition() {
|
||||
Timber.i("hillshade-highlight-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHillshadeHighlightColorTransition(options);
|
||||
assertEquals(layer.getHillshadeHighlightColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeHighlightColorAsConstant() {
|
||||
Timber.i("hillshade-highlight-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeHighlightColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(hillshadeHighlightColor(propertyValue));
|
||||
assertEquals(layer.getHillshadeHighlightColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeHighlightColorAsIntConstant() {
|
||||
Timber.i("hillshade-highlight-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(hillshadeHighlightColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getHillshadeHighlightColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeAccentColorTransition() {
|
||||
Timber.i("hillshade-accent-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setHillshadeAccentColorTransition(options);
|
||||
assertEquals(layer.getHillshadeAccentColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeAccentColorAsConstant() {
|
||||
Timber.i("hillshade-accent-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getHillshadeAccentColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(hillshadeAccentColor(propertyValue));
|
||||
assertEquals(layer.getHillshadeAccentColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testHillshadeAccentColorAsIntConstant() {
|
||||
Timber.i("hillshade-accent-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(hillshadeAccentColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getHillshadeAccentColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.maplibre.android.testapp.style
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* CRUD tests around Image
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class ImageTest : EspressoTest() {
|
||||
|
||||
companion object {
|
||||
private const val IMAGE_ID = "test.image"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddGetImage() {
|
||||
validateTestSetup()
|
||||
MapLibreMapAction.invoke(maplibreMap) { uiController, mapboxMap ->
|
||||
val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round)
|
||||
assertTrue(drawable is BitmapDrawable)
|
||||
|
||||
val bitmapSet = (drawable as BitmapDrawable).bitmap
|
||||
mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet)
|
||||
|
||||
// adding an image requires converting the image with an asynctask
|
||||
uiController.loopMainThreadForAtLeast(200)
|
||||
|
||||
val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID)
|
||||
assertTrue(bitmapGet!!.similarTo(bitmapSet))
|
||||
|
||||
mapboxMap.style!!.removeImage(IMAGE_ID)
|
||||
assertNull(mapboxMap.style!!.getImage(IMAGE_ID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative implementation of Bitmap.sameAs #14060
|
||||
*/
|
||||
fun Bitmap.similarTo(other: Bitmap): Boolean {
|
||||
if (invalidConfig(other)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Allocate arrays
|
||||
val argb = IntArray(width * height)
|
||||
val argbOther = IntArray(other.width * other.height)
|
||||
getPixels(argb, 0, width, 0, 0, width, height)
|
||||
other.getPixels(argbOther, 0, width, 0, 0, width, height)
|
||||
|
||||
// Alpha channel special check
|
||||
if (config == Bitmap.Config.ALPHA_8) {
|
||||
// in this case we have to manually compare the alpha channel as the rest is garbage.
|
||||
val length = width * height
|
||||
for (i in 0 until length) {
|
||||
if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return Arrays.equals(argb, argbOther)
|
||||
}
|
||||
|
||||
fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height
|
||||
@@ -0,0 +1,172 @@
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
import android.view.View;
|
||||
|
||||
import org.maplibre.android.style.light.Light;
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.FillExtrusionLayer;
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import org.maplibre.android.style.light.Position;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.style.FillExtrusionStyleTestActivity;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.maplibre.android.style.expressions.Expression.eq;
|
||||
import static org.maplibre.android.style.layers.Property.ANCHOR_MAP;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionBase;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionHeight;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionOpacity;
|
||||
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class LightTest extends BaseTest {
|
||||
|
||||
private Light light;
|
||||
|
||||
@Test
|
||||
public void testAnchor() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("anchor");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
light.setAnchor(ANCHOR_MAP);
|
||||
assertEquals("Anchor should match", ANCHOR_MAP, light.getAnchor());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPositionTransition() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("positionTransitionOptions");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
light.setPositionTransition(options);
|
||||
assertEquals("Transition options should match", options, light.getPositionTransition());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPosition() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("position");
|
||||
invoke(maplibreMap,(uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
Position position = new Position(1, 2, 3);
|
||||
light.setPosition(position);
|
||||
assertEquals("Position should match", position, light.getPosition());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColorTransition() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("colorTransitionOptions");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
light.setColorTransition(options);
|
||||
assertEquals("Transition options should match", options, light.getColorTransition());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColor() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("color");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
light.setColor("rgba(255,128,0,0.7)");
|
||||
assertEquals("Color should match", "rgba(255,128,0,0.7)", light.getColor());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntensityTransition() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("intensityTransitionOptions");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
light.setIntensityTransition(options);
|
||||
assertEquals("Transition options should match", options, light.getIntensityTransition());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntensity() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("intensity");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
light.setIntensity(0.3f);
|
||||
assertEquals("Intensity should match", 0.3f, light.getIntensity(), 0f);
|
||||
});
|
||||
}
|
||||
|
||||
private void setupLight() {
|
||||
onView(withId(R.id.mapView)).perform(new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
light = maplibreMap.getStyle().getLight();
|
||||
FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
|
||||
fillExtrusionLayer.setSourceLayer("building");
|
||||
fillExtrusionLayer.setFilter(eq(Expression.get("extrude"), "true"));
|
||||
fillExtrusionLayer.setMinZoom(15);
|
||||
fillExtrusionLayer.setProperties(
|
||||
fillExtrusionColor(Color.LTGRAY),
|
||||
fillExtrusionHeight(Expression.get("height")),
|
||||
fillExtrusionBase(Expression.get("min_height")),
|
||||
fillExtrusionOpacity(0.6f)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(fillExtrusionLayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return FillExtrusionStyleTestActivity.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.LineLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for LineLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class LineLayerTest extends BaseLayerTest {
|
||||
|
||||
private LineLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new LineLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineCapAsConstant() {
|
||||
Timber.i("line-cap");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineCap().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = LINE_CAP_BUTT;
|
||||
layer.setProperties(lineCap(propertyValue));
|
||||
assertEquals(layer.getLineCap().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineJoinAsConstant() {
|
||||
Timber.i("line-join");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineJoin().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = LINE_JOIN_BEVEL;
|
||||
layer.setProperties(lineJoin(propertyValue));
|
||||
assertEquals(layer.getLineJoin().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineJoinAsExpression() {
|
||||
Timber.i("line-join-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineJoin().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = string(Expression.get("undefined"));
|
||||
layer.setProperties(lineJoin(expression));
|
||||
assertEquals(layer.getLineJoin().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineMiterLimitAsConstant() {
|
||||
Timber.i("line-miter-limit");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineMiterLimit().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineMiterLimit(propertyValue));
|
||||
assertEquals(layer.getLineMiterLimit().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineRoundLimitAsConstant() {
|
||||
Timber.i("line-round-limit");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineRoundLimit().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineRoundLimit(propertyValue));
|
||||
assertEquals(layer.getLineRoundLimit().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineSortKeyAsConstant() {
|
||||
Timber.i("line-sort-key");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineSortKey().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineSortKey(propertyValue));
|
||||
assertEquals(layer.getLineSortKey().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineSortKeyAsExpression() {
|
||||
Timber.i("line-sort-key-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineSortKey().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(lineSortKey(expression));
|
||||
assertEquals(layer.getLineSortKey().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineOpacityTransition() {
|
||||
Timber.i("line-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineOpacityTransition(options);
|
||||
assertEquals(layer.getLineOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineOpacityAsConstant() {
|
||||
Timber.i("line-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineOpacity(propertyValue));
|
||||
assertEquals(layer.getLineOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineOpacityAsExpression() {
|
||||
Timber.i("line-opacity-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineOpacity().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(lineOpacity(expression));
|
||||
assertEquals(layer.getLineOpacity().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineColorTransition() {
|
||||
Timber.i("line-colorTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineColorTransition(options);
|
||||
assertEquals(layer.getLineColorTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineColorAsConstant() {
|
||||
Timber.i("line-color");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineColor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "rgba(255,128,0,0.7)";
|
||||
layer.setProperties(lineColor(propertyValue));
|
||||
assertEquals(layer.getLineColor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineColorAsExpression() {
|
||||
Timber.i("line-color-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineColor().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = toColor(Expression.get("undefined"));
|
||||
layer.setProperties(lineColor(expression));
|
||||
assertEquals(layer.getLineColor().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineColorAsIntConstant() {
|
||||
Timber.i("line-color");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(lineColor(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.getLineColorAsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineTranslateTransition() {
|
||||
Timber.i("line-translateTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineTranslateTransition(options);
|
||||
assertEquals(layer.getLineTranslateTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineTranslateAsConstant() {
|
||||
Timber.i("line-translate");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineTranslate().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float[] propertyValue = new Float[] {0f, 0f};
|
||||
layer.setProperties(lineTranslate(propertyValue));
|
||||
assertEquals(layer.getLineTranslate().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineTranslateAnchorAsConstant() {
|
||||
Timber.i("line-translate-anchor");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineTranslateAnchor().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = LINE_TRANSLATE_ANCHOR_MAP;
|
||||
layer.setProperties(lineTranslateAnchor(propertyValue));
|
||||
assertEquals(layer.getLineTranslateAnchor().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineWidthTransition() {
|
||||
Timber.i("line-widthTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineWidthTransition(options);
|
||||
assertEquals(layer.getLineWidthTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineWidthAsConstant() {
|
||||
Timber.i("line-width");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineWidth().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineWidth(propertyValue));
|
||||
assertEquals(layer.getLineWidth().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineWidthAsExpression() {
|
||||
Timber.i("line-width-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineWidth().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(lineWidth(expression));
|
||||
assertEquals(layer.getLineWidth().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineGapWidthTransition() {
|
||||
Timber.i("line-gap-widthTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineGapWidthTransition(options);
|
||||
assertEquals(layer.getLineGapWidthTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineGapWidthAsConstant() {
|
||||
Timber.i("line-gap-width");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineGapWidth().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineGapWidth(propertyValue));
|
||||
assertEquals(layer.getLineGapWidth().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineGapWidthAsExpression() {
|
||||
Timber.i("line-gap-width-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineGapWidth().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(lineGapWidth(expression));
|
||||
assertEquals(layer.getLineGapWidth().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineOffsetTransition() {
|
||||
Timber.i("line-offsetTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineOffsetTransition(options);
|
||||
assertEquals(layer.getLineOffsetTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineOffsetAsConstant() {
|
||||
Timber.i("line-offset");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineOffset().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineOffset(propertyValue));
|
||||
assertEquals(layer.getLineOffset().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineBlurTransition() {
|
||||
Timber.i("line-blurTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineBlurTransition(options);
|
||||
assertEquals(layer.getLineBlurTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineBlurAsConstant() {
|
||||
Timber.i("line-blur");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineBlur().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(lineBlur(propertyValue));
|
||||
assertEquals(layer.getLineBlur().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineBlurAsExpression() {
|
||||
Timber.i("line-blur-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineBlur().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = number(Expression.get("undefined"));
|
||||
layer.setProperties(lineBlur(expression));
|
||||
assertEquals(layer.getLineBlur().getExpression(), expression);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineDasharrayTransition() {
|
||||
Timber.i("line-dasharrayTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLineDasharrayTransition(options);
|
||||
assertEquals(layer.getLineDasharrayTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLineDasharrayAsConstant() {
|
||||
Timber.i("line-dasharray");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLineDasharray().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float[] propertyValue = new Float[] {};
|
||||
layer.setProperties(lineDasharray(propertyValue));
|
||||
assertEquals(layer.getLineDasharray().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLinePatternTransition() {
|
||||
Timber.i("line-patternTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setLinePatternTransition(options);
|
||||
assertEquals(layer.getLinePatternTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLinePatternAsConstant() {
|
||||
Timber.i("line-pattern");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLinePattern().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = "pedestrian-polygon";
|
||||
layer.setProperties(linePattern(propertyValue));
|
||||
assertEquals(layer.getLinePattern().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testLinePatternAsExpression() {
|
||||
Timber.i("line-pattern-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getLinePattern().getExpression());
|
||||
|
||||
// Set and Get
|
||||
Expression expression = image(string(Expression.get("undefined")));
|
||||
layer.setProperties(linePattern(expression));
|
||||
assertEquals(layer.getLinePattern().getExpression(), expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.RasterLayer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for RasterLayer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class RasterLayerTest extends BaseLayerTest {
|
||||
|
||||
private RasterLayer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
layer = new RasterLayer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
setupLayer(layer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterOpacityTransition() {
|
||||
Timber.i("raster-opacityTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterOpacityTransition(options);
|
||||
assertEquals(layer.getRasterOpacityTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterOpacityAsConstant() {
|
||||
Timber.i("raster-opacity");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterOpacity().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterOpacity(propertyValue));
|
||||
assertEquals(layer.getRasterOpacity().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterHueRotateTransition() {
|
||||
Timber.i("raster-hue-rotateTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterHueRotateTransition(options);
|
||||
assertEquals(layer.getRasterHueRotateTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterHueRotateAsConstant() {
|
||||
Timber.i("raster-hue-rotate");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterHueRotate().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterHueRotate(propertyValue));
|
||||
assertEquals(layer.getRasterHueRotate().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterBrightnessMinTransition() {
|
||||
Timber.i("raster-brightness-minTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterBrightnessMinTransition(options);
|
||||
assertEquals(layer.getRasterBrightnessMinTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterBrightnessMinAsConstant() {
|
||||
Timber.i("raster-brightness-min");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterBrightnessMin().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterBrightnessMin(propertyValue));
|
||||
assertEquals(layer.getRasterBrightnessMin().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterBrightnessMaxTransition() {
|
||||
Timber.i("raster-brightness-maxTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterBrightnessMaxTransition(options);
|
||||
assertEquals(layer.getRasterBrightnessMaxTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterBrightnessMaxAsConstant() {
|
||||
Timber.i("raster-brightness-max");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterBrightnessMax().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterBrightnessMax(propertyValue));
|
||||
assertEquals(layer.getRasterBrightnessMax().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterSaturationTransition() {
|
||||
Timber.i("raster-saturationTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterSaturationTransition(options);
|
||||
assertEquals(layer.getRasterSaturationTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterSaturationAsConstant() {
|
||||
Timber.i("raster-saturation");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterSaturation().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterSaturation(propertyValue));
|
||||
assertEquals(layer.getRasterSaturation().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterContrastTransition() {
|
||||
Timber.i("raster-contrastTransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.setRasterContrastTransition(options);
|
||||
assertEquals(layer.getRasterContrastTransition(), options);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterContrastAsConstant() {
|
||||
Timber.i("raster-contrast");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterContrast().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterContrast(propertyValue));
|
||||
assertEquals(layer.getRasterContrast().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterResamplingAsConstant() {
|
||||
Timber.i("raster-resampling");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterResampling().getValue());
|
||||
|
||||
// Set and Get
|
||||
String propertyValue = RASTER_RESAMPLING_LINEAR;
|
||||
layer.setProperties(rasterResampling(propertyValue));
|
||||
assertEquals(layer.getRasterResampling().getValue(), propertyValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testRasterFadeDurationAsConstant() {
|
||||
Timber.i("raster-fade-duration");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.getRasterFadeDuration().getValue());
|
||||
|
||||
// Set and Get
|
||||
Float propertyValue = 0.3f;
|
||||
layer.setProperties(rasterFadeDuration(propertyValue));
|
||||
assertEquals(layer.getRasterFadeDuration().getValue(), propertyValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import org.maplibre.android.style.layers.CannotAddLayerException;
|
||||
import org.maplibre.android.style.layers.CircleLayer;
|
||||
import org.maplibre.android.style.layers.FillLayer;
|
||||
import org.maplibre.android.style.layers.Layer;
|
||||
import org.maplibre.android.style.layers.LineLayer;
|
||||
import org.maplibre.android.style.layers.Property;
|
||||
import org.maplibre.android.style.layers.PropertyFactory;
|
||||
import org.maplibre.android.style.sources.CannotAddSourceException;
|
||||
import org.maplibre.android.style.sources.GeoJsonSource;
|
||||
import org.maplibre.android.style.sources.RasterSource;
|
||||
import org.maplibre.android.style.sources.Source;
|
||||
import org.maplibre.android.style.sources.VectorSource;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.EspressoTest;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for Layer and Source
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class RuntimeStyleTests extends EspressoTest {
|
||||
|
||||
@Test
|
||||
public void testListLayers() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
List<Layer> layers = maplibreMap.getStyle().getLayers();
|
||||
assertNotNull(layers);
|
||||
assertTrue(layers.size() > 0);
|
||||
for (Layer layer : layers) {
|
||||
assertNotNull(layer);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddRemoveLayer() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new AddRemoveLayerAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLayerAbove() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
List<Layer> layers = maplibreMap.getStyle().getLayers();
|
||||
Source source = maplibreMap.getStyle().getSources().get(0);
|
||||
|
||||
// Test inserting with invalid above-id
|
||||
try {
|
||||
maplibreMap.getStyle().addLayerAbove(
|
||||
new CircleLayer("invalid-id-layer-test", source.getId()), "no-such-layer-here-man"
|
||||
);
|
||||
fail("Should have thrown exception");
|
||||
} catch (CannotAddLayerException ex) {
|
||||
// Yeah
|
||||
assertNotNull(ex.getMessage());
|
||||
}
|
||||
|
||||
// Insert as last
|
||||
CircleLayer last = new CircleLayer("this is the last one", source.getId());
|
||||
maplibreMap.getStyle().addLayerAbove(last, layers.get(layers.size() - 1).getId());
|
||||
layers = maplibreMap.getStyle().getLayers();
|
||||
assertEquals(last.getId(), layers.get(layers.size() - 1).getId());
|
||||
|
||||
// Insert
|
||||
CircleLayer second = new CircleLayer("this is the second one", source.getId());
|
||||
maplibreMap.getStyle().addLayerAbove(second, layers.get(0).getId());
|
||||
layers = maplibreMap.getStyle().getLayers();
|
||||
assertEquals(second.getId(), layers.get(1).getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveLayerAt() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
// Remove by index
|
||||
Layer firstLayer = maplibreMap.getStyle().getLayers().get(0);
|
||||
boolean removed = maplibreMap.getStyle().removeLayerAt(0);
|
||||
assertTrue(removed);
|
||||
assertNotNull(firstLayer);
|
||||
|
||||
// Test remove by index bounds checks
|
||||
Timber.i("Remove layer at index > size");
|
||||
assertFalse(maplibreMap.getStyle().removeLayerAt(Integer.MAX_VALUE));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLayerAt() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
List<Layer> layers = maplibreMap.getStyle().getLayers();
|
||||
Source source = maplibreMap.getStyle().getSources().get(0);
|
||||
|
||||
// Test inserting out of range
|
||||
try {
|
||||
maplibreMap.getStyle().addLayerAt(new CircleLayer("invalid-id-layer-test", source.getId()), layers.size());
|
||||
fail("Should have thrown exception");
|
||||
} catch (CannotAddLayerException ex) {
|
||||
// Yeah
|
||||
assertNotNull(ex.getMessage());
|
||||
}
|
||||
|
||||
// Insert at current last position
|
||||
CircleLayer last = new CircleLayer("this is the last one", source.getId());
|
||||
maplibreMap.getStyle().addLayerAt(last, layers.size() - 1);
|
||||
layers = maplibreMap.getStyle().getLayers();
|
||||
assertEquals(last.getId(), layers.get(layers.size() - 2).getId());
|
||||
|
||||
// Insert at start
|
||||
CircleLayer second = new CircleLayer("this is the first one", source.getId());
|
||||
maplibreMap.getStyle().addLayerAt(second, 0);
|
||||
layers = maplibreMap.getStyle().getLayers();
|
||||
assertEquals(second.getId(), layers.get(0).getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testListSources() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
List<Source> sources = maplibreMap.getStyle().getSources();
|
||||
assertNotNull(sources);
|
||||
assertTrue(sources.size() > 0);
|
||||
for (Source source : sources) {
|
||||
assertNotNull(source);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveSource() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
mapboxMap.getStyle().addSource(new VectorSource("my-source", "maptiler://sources/hillshades"));
|
||||
mapboxMap.getStyle().removeSource("my-source");
|
||||
|
||||
// Add initial source
|
||||
mapboxMap.getStyle().addSource(new VectorSource("my-source", "maptiler://sources/hillshades"));
|
||||
|
||||
// Remove
|
||||
boolean removeOk = mapboxMap.getStyle().removeSource("my-source");
|
||||
assertTrue(removeOk);
|
||||
assertNull(mapboxMap.getStyle().getLayer("my-source"));
|
||||
|
||||
// Add
|
||||
Source source = new VectorSource("my-source", "maptiler://sources/hillshades");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
|
||||
// Remove, preserving the reference
|
||||
mapboxMap.getStyle().removeSource(source);
|
||||
|
||||
// Re-add the reference...
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
|
||||
// Ensure it's there
|
||||
Assert.assertNotNull(mapboxMap.getStyle().getSource(source.getId()));
|
||||
|
||||
// Test adding a duplicate source
|
||||
try {
|
||||
Source source2 = new VectorSource("my-source", "maptiler://sources/hillshades");
|
||||
mapboxMap.getStyle().addSource(source2);
|
||||
fail("Should not have been allowed to add a source with a duplicate id");
|
||||
} catch (CannotAddSourceException cannotAddSourceException) {
|
||||
// OK
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVectorSourceUrlGetter() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
VectorSource source = new VectorSource("my-source", "maptiler://sources/hillshades");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
assertEquals("maptiler://sources/hillshades", source.getUri());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRasterSourceUrlGetter() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
RasterSource source = new RasterSource("my-source", "maptiler://sources/hillshades");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
assertEquals("maptiler://sources/hillshades", source.getUri());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeoJsonSourceUrlGetter() {
|
||||
validateTestSetup();
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
GeoJsonSource source = new GeoJsonSource("my-source");
|
||||
mapboxMap.getStyle().addSource(source);
|
||||
assertNull(source.getUri());
|
||||
source.setUri("http://mapbox.com/my-file.json");
|
||||
assertEquals("http://mapbox.com/my-file.json", source.getUri());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSourceInUse() {
|
||||
validateTestSetup();
|
||||
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
maplibreMap.getStyle().addSource(new VectorSource("my-source", "maptiler://sources/hillshades"));
|
||||
maplibreMap.getStyle().addLayer(new LineLayer("my-layer", "my-source"));
|
||||
maplibreMap.getStyle().removeSource("my-source");
|
||||
assertNotNull(maplibreMap.getStyle().getSource("my-source"));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveNonExistingSource() {
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> mapboxMap.getStyle().removeSource("source"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveNonExistingLayer() {
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
assertFalse(mapboxMap.getStyle().removeLayer("layer"));
|
||||
assertFalse(mapboxMap.getStyle().removeLayerAt(mapboxMap.getStyle().getLayers().size() + 1));
|
||||
assertFalse(mapboxMap.getStyle().removeLayerAt(-1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveExistingLayer() {
|
||||
invoke(maplibreMap, (uiController, mapboxMap) -> {
|
||||
Layer firstLayer = mapboxMap.getStyle().getLayers().get(0);
|
||||
assertTrue(mapboxMap.getStyle().removeLayer(firstLayer));
|
||||
|
||||
firstLayer = mapboxMap.getStyle().getLayers().get(0);
|
||||
assertTrue(mapboxMap.getStyle().removeLayer(firstLayer.getId()));
|
||||
|
||||
assertTrue(mapboxMap.getStyle().removeLayerAt(0));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/7973
|
||||
*/
|
||||
@Test
|
||||
public void testQueryRenderedFeaturesInputHandling() {
|
||||
validateTestSetup();
|
||||
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
String[] layerIds = new String[600];
|
||||
for (int i = 0; i < layerIds.length; i++) {
|
||||
layerIds[i] = "layer-" + i;
|
||||
}
|
||||
maplibreMap.queryRenderedFeatures(new PointF(100, 100), layerIds);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private class AddRemoveLayerAction extends BaseViewAction {
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
// Get initial
|
||||
assertNotNull(maplibreMap.getStyle().getLayer("building"));
|
||||
|
||||
// Remove
|
||||
boolean removed = maplibreMap.getStyle().removeLayer("building");
|
||||
assertTrue(removed);
|
||||
assertNull(maplibreMap.getStyle().getLayer("building"));
|
||||
|
||||
// Add
|
||||
FillLayer layer = new FillLayer("building", "composite");
|
||||
layer.setSourceLayer("building");
|
||||
maplibreMap.getStyle().addLayer(layer);
|
||||
assertNotNull(maplibreMap.getStyle().getLayer("building"));
|
||||
|
||||
// Assure the reference still works
|
||||
layer.setProperties(PropertyFactory.visibility(Property.VISIBLE));
|
||||
|
||||
// Remove, preserving the reference
|
||||
maplibreMap.getStyle().removeLayer(layer);
|
||||
|
||||
// Property setters should still work
|
||||
layer.setProperties(PropertyFactory.fillColor(Color.RED));
|
||||
|
||||
// Re-add the reference...
|
||||
maplibreMap.getStyle().addLayer(layer);
|
||||
|
||||
// Ensure it's there
|
||||
Assert.assertNotNull(maplibreMap.getStyle().getLayer(layer.getId()));
|
||||
|
||||
// Test adding a duplicate layer
|
||||
try {
|
||||
maplibreMap.getStyle().addLayer(new FillLayer("building", "composite"));
|
||||
fail("Should not have been allowed to add a layer with a duplicate id");
|
||||
} catch (CannotAddLayerException cannotAddLayerException) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BaseViewAction implements ViewAction {
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.style.RuntimeStyleTimingTestActivity;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for adding Layer and Source as early as possible (in onCreate)
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class RuntimeStyleTimingTests extends BaseTest {
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return RuntimeStyleTimingTestActivity.class;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAddRemoveLayer() {
|
||||
validateTestSetup();
|
||||
// We're good if it didn't crash
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.maplibre.android.testapp.style
|
||||
|
||||
import android.view.View
|
||||
import androidx.test.espresso.UiController
|
||||
import org.maplibre.android.maps.MapView
|
||||
import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.android.testapp.action.MapLibreMapAction
|
||||
import org.maplibre.android.testapp.activity.EspressoTest
|
||||
import org.maplibre.android.testapp.utils.ResourceUtils.readRawResource
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Tests around style loading
|
||||
*/
|
||||
class StyleLoaderTest : EspressoTest() {
|
||||
@Test
|
||||
fun testSetGetStyleJsonString() {
|
||||
validateTestSetup()
|
||||
MapLibreMapAction.invoke(
|
||||
maplibreMap
|
||||
) { uiController: UiController?, maplibreMap: MapLibreMap ->
|
||||
try {
|
||||
val expected =
|
||||
readRawResource(
|
||||
rule.activity,
|
||||
R.raw.local_style
|
||||
)
|
||||
maplibreMap.setStyle(Style.Builder().fromJson(expected))
|
||||
val actual = maplibreMap.style!!.json
|
||||
Assert.assertEquals("Style json should match", expected, actual)
|
||||
} catch (exception: IOException) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDefaultStyleLoadWithActivityLifecycleChange() {
|
||||
validateTestSetup()
|
||||
MapLibreMapAction.invoke(
|
||||
maplibreMap
|
||||
) { uiController: UiController?, maplibreMap: MapLibreMap ->
|
||||
try {
|
||||
val expected =
|
||||
readRawResource(
|
||||
rule.activity,
|
||||
R.raw.local_style
|
||||
)
|
||||
maplibreMap.setStyle(Style.Builder().fromJson(expected))
|
||||
|
||||
// fake activity stop/start
|
||||
val mapView =
|
||||
rule.activity.findViewById<View>(R.id.mapView) as MapView
|
||||
mapView.onPause()
|
||||
mapView.onStop()
|
||||
mapView.onStart()
|
||||
mapView.onResume()
|
||||
val actual = maplibreMap.style!!.json
|
||||
Assert.assertEquals(
|
||||
"Style URL should be empty",
|
||||
"",
|
||||
maplibreMap.style!!.uri
|
||||
)
|
||||
Assert.assertEquals("Style json should match", expected, actual)
|
||||
} catch (exception: IOException) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
<%
|
||||
const type = locals.type;
|
||||
const properties = locals.properties;
|
||||
-%>
|
||||
// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`.
|
||||
|
||||
<% if (type === 'location-indicator') { -%>
|
||||
package org.maplibre.android.location;
|
||||
<% } else { -%>
|
||||
package org.maplibre.android.testapp.style;
|
||||
<% } -%>
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.mapbox.geojson.LineString;
|
||||
import com.mapbox.geojson.MultiLineString;
|
||||
import com.mapbox.geojson.MultiPoint;
|
||||
import com.mapbox.geojson.MultiPolygon;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.geojson.Polygon;
|
||||
import org.maplibre.android.maps.BaseLayerTest;
|
||||
import org.junit.Before;
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
<% if (type !== 'location-indicator') { -%>
|
||||
import org.maplibre.android.style.layers.<%- camelize(type) %>Layer;
|
||||
<% } -%>
|
||||
<% if (type === 'symbol') { -%>
|
||||
import org.maplibre.android.style.types.Formatted;
|
||||
import org.maplibre.android.style.types.FormattedSection;
|
||||
<% } -%>
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.maplibre.android.style.expressions.Expression.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.maplibre.android.style.layers.Property.*;
|
||||
<% if (type === 'location-indicator') { -%>
|
||||
import static org.maplibre.android.location.LocationPropertyFactory.*;
|
||||
<% } else { -%>
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.*;
|
||||
<% } -%>
|
||||
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic smoke tests for <%- camelize(type) %>Layer
|
||||
*/
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class <%- camelize(type) %>LayerTest extends BaseLayerTest {
|
||||
|
||||
private <%- camelize(type) %>Layer layer;
|
||||
private final List<Point> pointsList = new ArrayList<Point>() {
|
||||
{
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
add(Point.fromLngLat(55.29743486255916, 25.25827212207261));
|
||||
add(Point.fromLngLat(55.28978863411328, 25.251356725509737));
|
||||
add(Point.fromLngLat(55.300027931336984, 25.246425506635504));
|
||||
add(Point.fromLngLat(55.307474692951274, 25.244200378933655));
|
||||
add(Point.fromLngLat(55.31212891895635, 25.256408010450187));
|
||||
add(Point.fromLngLat(55.30774064871093, 25.26266169122738));
|
||||
add(Point.fromLngLat(55.301357710197806, 25.264946609615492));
|
||||
add(Point.fromLngLat(55.30122473231012, 25.26476622289597));
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void beforeTest(){
|
||||
super.before();
|
||||
<% if (type === 'background' || type === 'location-indicator') { -%>
|
||||
layer = new <%- camelize(type) %>Layer("my-layer");
|
||||
<% } else { -%>
|
||||
layer = new <%- camelize(type) %>Layer("my-layer", "composite");
|
||||
layer.setSourceLayer("composite");
|
||||
<% } -%>
|
||||
setupLayer(layer);
|
||||
}
|
||||
<% if (type !== 'background' && type !== 'location-indicator') { -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceId() {
|
||||
Timber.i("SourceId");
|
||||
assertNotNull(layer);
|
||||
assertEquals(layer.getSourceId(), "composite");
|
||||
}
|
||||
<% } -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSetVisibility() {
|
||||
Timber.i("Visibility");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getVisibility().getValue(), VISIBLE);
|
||||
|
||||
// Set
|
||||
layer.setProperties(visibility(NONE));
|
||||
assertEquals(layer.getVisibility().getValue(), NONE);
|
||||
}
|
||||
<% if (!(type === 'background' || type === 'location-indicator' || type === 'raster' || type === 'hillshade')) { -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testSourceLayer() {
|
||||
Timber.i("SourceLayer");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getSourceLayer(), "composite");
|
||||
|
||||
// Set
|
||||
final String sourceLayer = "test";
|
||||
layer.setSourceLayer(sourceLayer);
|
||||
assertEquals(layer.getSourceLayer(), sourceLayer);
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilter() {
|
||||
Timber.i("Filter");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// Set
|
||||
Expression filter = eq(get("undefined"), literal(1.0));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// Set constant
|
||||
filter = literal(true);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterDistance() {
|
||||
Timber.i("FilterDistance");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
// distance with Point
|
||||
Expression filter = lt(distance(Point.fromLngLat(1.0, 1.0)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with LineString
|
||||
filter = lt(distance(LineString.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiPoint.fromLngLats(pointsList)), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPoint
|
||||
filter = lt(distance(MultiLineString.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with Polygon
|
||||
filter = lt(distance(Polygon.fromLngLats(Collections.singletonList(pointsList))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
|
||||
// distance with MultiPolygon
|
||||
filter = lt(distance(MultiPolygon.fromLngLats(Collections
|
||||
.singletonList(Collections.singletonList(pointsList)))), 50);
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void testFilterWithin() {
|
||||
Timber.i("FilterWithin");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Get initial
|
||||
assertEquals(layer.getFilter(), null);
|
||||
|
||||
Expression filter = within(Polygon.fromLngLats(Collections.singletonList(pointsList)));
|
||||
layer.setFilter(filter);
|
||||
assertEquals(layer.getFilter().toString(), filter.toString());
|
||||
}
|
||||
|
||||
<% } -%>
|
||||
<% for (const property of properties) { -%>
|
||||
<% if (property['property-type'] !== 'color-ramp') { -%>
|
||||
<% if (property.transition) { -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void test<%- camelize(property.name) %>Transition() {
|
||||
Timber.i("<%- property.name %>TransitionOptions");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
layer.set<%- camelize(property.name) %>Transition(options);
|
||||
assertEquals(layer.get<%- camelize(property.name) %>Transition(), options);
|
||||
}
|
||||
<% } -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void test<%- camelize(property.name) %>AsConstant() {
|
||||
Timber.i("<%- property.name %>");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.get<%- camelize(property.name) %>().getValue());
|
||||
|
||||
// Set and Get
|
||||
<%- propertyType(property) %> propertyValue = <%- defaultValueJava(property) %>;
|
||||
<% if (property.type === 'formatted') { -%>
|
||||
layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>("default"));
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getValue(), propertyValue);
|
||||
<% } -%>
|
||||
layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(propertyValue));
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getValue(), propertyValue);
|
||||
<% if (property.tokens) { -%>
|
||||
|
||||
layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>("{token}"));
|
||||
<% if (property.type === 'formatted') { -%>
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), <%- defaultExpressionJava(property) %>(Expression.formatEntry(Expression.toString(Expression.get("token")))));
|
||||
<% } else if (property.type === 'resolvedImage') {-%>
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), <%- defaultExpressionJava(property) %>(Expression.toString(Expression.get("token"))));
|
||||
<% } else {-%>
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), Expression.toString(Expression.get("token")));
|
||||
<% } -%>
|
||||
<% } -%>
|
||||
}
|
||||
<% if (property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven') { -%>
|
||||
<% if (!(property.name.endsWith("-font")||property.name.endsWith("-offset"))) { -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void test<%- camelize(property.name) %>AsExpression() {
|
||||
Timber.i("<%- property.name %>-expression");
|
||||
assertNotNull(layer);
|
||||
assertNull(layer.get<%- camelize(property.name) %>().getExpression());
|
||||
|
||||
// Set and Get
|
||||
<% if (property.type === 'formatted') { -%>
|
||||
Expression expression = <%- defaultExpressionJava(property) %>(Expression.formatEntry(Expression.get("undefined"), FormatOption.formatFontScale(2.0), FormatOption.formatTextFont(new String[]{"Open Sans Regular", "Arial Unicode MS Regular"})));
|
||||
<% } else if (property.type === 'resolvedImage') { -%>
|
||||
Expression expression = <%- defaultExpressionJava(property) %>(string(Expression.get("undefined")));
|
||||
<% } else { -%>
|
||||
Expression expression = <%- defaultExpressionJava(property) %>(Expression.get("undefined"));
|
||||
<% } -%>
|
||||
layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(expression));
|
||||
assertEquals(layer.get<%- camelize(property.name) %>().getExpression(), expression);
|
||||
}
|
||||
<% } -%>
|
||||
<% } -%>
|
||||
<% if (property.type == 'color') { -%>
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
public void test<%- camelize(property.name) %>AsIntConstant() {
|
||||
Timber.i("<%- property.name %>");
|
||||
assertNotNull(layer);
|
||||
|
||||
// Set and Get
|
||||
layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(Color.argb(127, 255, 127, 0)));
|
||||
assertEquals(layer.get<%- camelize(property.name) %>AsInt(), Color.argb(127, 255, 127, 0));
|
||||
}
|
||||
<% } -%>
|
||||
<% } -%>
|
||||
<% } -%>
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<%
|
||||
const properties = locals.properties;
|
||||
-%>
|
||||
package org.maplibre.android.testapp.style;
|
||||
|
||||
import android.graphics.Color;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
import android.view.View;
|
||||
|
||||
import org.maplibre.android.style.light.Light;
|
||||
import org.maplibre.android.style.expressions.Expression;
|
||||
import org.maplibre.android.style.layers.FillExtrusionLayer;
|
||||
import org.maplibre.android.style.layers.TransitionOptions;
|
||||
import org.maplibre.android.style.light.Position;
|
||||
import org.maplibre.android.testapp.R;
|
||||
import org.maplibre.android.testapp.activity.BaseTest;
|
||||
import org.maplibre.android.testapp.activity.style.FillExtrusionStyleTestActivity;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.maplibre.android.style.expressions.Expression.eq;
|
||||
import static org.maplibre.android.style.layers.Property.ANCHOR_MAP;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionBase;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionColor;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionHeight;
|
||||
import static org.maplibre.android.style.layers.PropertyFactory.fillExtrusionOpacity;
|
||||
|
||||
import static org.maplibre.android.testapp.action.MapLibreMapAction.invoke;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class LightTest extends BaseTest {
|
||||
|
||||
private Light light;
|
||||
<% for (const property of properties) { -%>
|
||||
<% if (property.transition) { -%>
|
||||
|
||||
@Test
|
||||
public void test<%- camelize(property.name) %>Transition() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("<%- property.name %>TransitionOptions");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
TransitionOptions options = new TransitionOptions(300, 100);
|
||||
light.set<%- camelize(property.name) %>Transition(options);
|
||||
assertEquals("Transition options should match", options, light.get<%- camelize(property.name) %>Transition());
|
||||
});
|
||||
}
|
||||
<% } -%>
|
||||
<% if (property.name == "position") { -%>
|
||||
|
||||
@Test
|
||||
public void test<%- camelize(property.name) %>() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("<%- property.name %>");
|
||||
invoke(maplibreMap,(uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
Position position = new Position(1, 2, 3);
|
||||
light.set<%- camelize(property.name) %>(position);
|
||||
assertEquals("Position should match", position, light.get<%- camelize(property.name) %>());
|
||||
});
|
||||
}
|
||||
<% } else { -%>
|
||||
|
||||
@Test
|
||||
public void test<%- camelize(property.name) %>() {
|
||||
validateTestSetup();
|
||||
setupLight();
|
||||
Timber.i("<%- property.name %>");
|
||||
invoke(maplibreMap, (uiController, maplibreMap) -> {
|
||||
assertNotNull(light);
|
||||
// Set and Get
|
||||
light.set<%- camelize(property.name) %>(<%- defaultValueJava(property) %>);
|
||||
<% if (property.name == 'color') { -%>
|
||||
assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>, light.get<%- camelize(property.name) %>());
|
||||
<% } else { -%>
|
||||
assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>, light.get<%- camelize(property.name) %>()<%- property.type === 'number' ? ', 0f' : '' %>);
|
||||
<% } -%>
|
||||
});
|
||||
}
|
||||
<% } -%>
|
||||
<% } -%>
|
||||
|
||||
private void setupLight() {
|
||||
onView(withId(R.id.mapView)).perform(new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
light = maplibreMap.getStyle().getLight();
|
||||
FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
|
||||
fillExtrusionLayer.setSourceLayer("building");
|
||||
fillExtrusionLayer.setFilter(eq(Expression.get("extrude"), "true"));
|
||||
fillExtrusionLayer.setMinZoom(15);
|
||||
fillExtrusionLayer.setProperties(
|
||||
fillExtrusionColor(Color.LTGRAY),
|
||||
fillExtrusionHeight(Expression.get("height")),
|
||||
fillExtrusionBase(Expression.get("min_height")),
|
||||
fillExtrusionOpacity(0.6f)
|
||||
);
|
||||
maplibreMap.getStyle().addLayer(fillExtrusionLayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class getActivityClass() {
|
||||
return FillExtrusionStyleTestActivity.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.maplibre.android.testapp.utils;
|
||||
|
||||
import androidx.test.espresso.IdlingResource;
|
||||
|
||||
import org.maplibre.android.testapp.activity.render.RenderTestActivity;
|
||||
|
||||
public class SnapshotterIdlingResource implements IdlingResource, RenderTestActivity.OnRenderTestCompletionListener {
|
||||
|
||||
private IdlingResource.ResourceCallback resourceCallback;
|
||||
private boolean isSnapshotReady;
|
||||
|
||||
public SnapshotterIdlingResource(RenderTestActivity activity) {
|
||||
activity.setOnRenderTestCompletionListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "SnapshotterIdlingResource";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIdleNow() {
|
||||
return isSnapshotReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
|
||||
this.resourceCallback = resourceCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
isSnapshotReady = true;
|
||||
if (resourceCallback != null) {
|
||||
resourceCallback.onTransitionToIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.maplibre.android.testapp.utils;
|
||||
|
||||
public class TestConstants {
|
||||
public static final double LAT_LNG_DELTA = 0.1;
|
||||
public static final double BEARING_DELTA = 0.1;
|
||||
public static final double TILT_DELTA = 0.3;
|
||||
public static final double ZOOM_DELTA = 0.3;
|
||||
public static final double PADDING_DELTA = 0.0001;
|
||||
|
||||
public static final String TEXT_MARKER_TITLE = "Marker";
|
||||
public static final String TEXT_MARKER_SNIPPET = "Snippet";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.maplibre.android.testapp.utils
|
||||
|
||||
import androidx.test.espresso.UiController
|
||||
import org.maplibre.android.maps.MapView
|
||||
|
||||
object TestingAsyncUtils {
|
||||
private const val DEFAULT_TIMEOUT = 15_000L
|
||||
|
||||
fun waitForLayer(uiController: UiController, mapView: MapView) {
|
||||
val start = System.nanoTime() / 1E6
|
||||
var isIdle = false
|
||||
mapView.addOnDidBecomeIdleListener { isIdle = true }
|
||||
|
||||
while (!isIdle && System.nanoTime() / 1E6 - start < DEFAULT_TIMEOUT) {
|
||||
uiController.loopMainThreadForAtLeast(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.maplibre.android.utils
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import org.maplibre.android.constants.MapLibreConstants
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||
class FontUtilsTest {
|
||||
@Test
|
||||
fun testExtractedFontShouldMatchDefault() {
|
||||
val fonts = arrayOf("foo", "bar")
|
||||
val actual = FontUtils.extractValidFont(*fonts)
|
||||
Assert.assertEquals("Selected font should match", MapLibreConstants.DEFAULT_FONT, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExtractedFontShouldMatchMonospace() {
|
||||
val expected = "monospace"
|
||||
val fonts = arrayOf("foo", expected)
|
||||
val actual = FontUtils.extractValidFont(*fonts)
|
||||
Assert.assertEquals("Selected font should match", expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExtractedFontShouldBeNull() {
|
||||
val actual = FontUtils.extractValidFont()
|
||||
Assert.assertNull(actual)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user