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)
|
||||
}
|
||||
}
|
||||
1239
platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml
Normal file
1239
platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
BIN
platform/android/MapLibreAndroidTestApp/src/main/assets/commercial-24.png
Executable file
BIN
platform/android/MapLibreAndroidTestApp/src/main/assets/commercial-24.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 308 B |
Binary file not shown.
|
After Width: | Height: | Size: 831 B |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user