Skip to content

Commit 83e3bc0

Browse files
committed
Merge branch “feature-ors”
2 parents ebea727 + bf287bd commit 83e3bc0

File tree

85 files changed

+2439
-718
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2439
-718
lines changed

app/src/main/java/org/nitri/opentopo/BaseMainActivity.kt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,16 @@ import org.nitri.opentopo.viewmodel.GpxViewModel
4545
import org.nitri.opentopo.nearby.NearbyFragment
4646
import org.nitri.opentopo.nearby.entity.NearbyItem
4747
import org.nitri.opentopo.util.Utils
48-
import org.nitri.ors.api.OpenRouteServiceApi
49-
import org.nitri.ors.client.OpenRouteServiceClient
5048
import org.osmdroid.util.GeoPoint
5149
import androidx.core.net.toUri
50+
import org.nitri.ors.DefaultOrsClient
51+
import org.nitri.ors.Ors
52+
import org.nitri.ors.OrsClient
5253

5354
open class BaseMainActivity : AppCompatActivity(), MapFragment.OnFragmentInteractionListener,
5455
GpxDetailFragment.OnFragmentInteractionListener, NearbyFragment.OnFragmentInteractionListener {
5556
private val parser = GPXParser()
56-
private var openRouteServiceApi: OpenRouteServiceApi? = null
57+
private var orsClient: OrsClient? = null
5758
private var geoPointFromIntent: GeoPointDto? = null
5859
private var gpxUriString: String? = null
5960
private var gpxUri: Uri? = null
@@ -83,7 +84,7 @@ open class BaseMainActivity : AppCompatActivity(), MapFragment.OnFragmentInterac
8384

8485
private val orsApiKeyChangesReceiver = object: BroadcastReceiver() {
8586
override fun onReceive(p0: Context?, intent: Intent?) {
86-
createOrsApi()
87+
createOrsClient()
8788
}
8889
}
8990

@@ -95,8 +96,8 @@ open class BaseMainActivity : AppCompatActivity(), MapFragment.OnFragmentInterac
9596
// NOP
9697
}
9798

98-
override fun getOpenRouteServiceApi(): OpenRouteServiceApi? {
99-
return openRouteServiceApi
99+
override fun getOpenRouteServiceClient(): OrsClient? {
100+
return orsClient
100101
}
101102

102103
private lateinit var sharedPreferences: SharedPreferences
@@ -182,13 +183,13 @@ open class BaseMainActivity : AppCompatActivity(), MapFragment.OnFragmentInterac
182183
// Log.d("ORS", "Distance: ${result.routes.firstOrNull()?.summary?.distance} m")
183184
// }
184185

185-
createOrsApi()
186+
createOrsClient()
186187
}
187188

188-
private fun createOrsApi() {
189+
private fun createOrsClient() {
189190
val apiKey = sharedPreferences.getString(PREF_ORS_API_KEY, "")
190191
if (apiKey?.isNotEmpty() == true) {
191-
openRouteServiceApi = OpenRouteServiceClient.create(apiKey, this@BaseMainActivity)
192+
orsClient = Ors.create(apiKey, applicationContext)
192193
}
193194
}
194195

app/src/main/java/org/nitri/opentopo/MapFragment.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import org.nitri.opentopo.util.OrientationSensor
5252
import org.nitri.opentopo.util.Utils
5353
import org.nitri.opentopo.viewmodel.LocationViewModel
5454
import org.nitri.opentopo.viewmodel.MarkerViewModel
55-
import org.nitri.ors.api.OpenRouteServiceApi
55+
import org.nitri.ors.OrsClient
5656
import org.osmdroid.config.Configuration
5757
import org.osmdroid.events.DelayedMapListener
5858
import org.osmdroid.events.MapEventsReceiver
@@ -398,10 +398,10 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe
398398
}
399399
val locale = Resources.getSystem().configuration.locales.get(0)
400400
val language = locale.toLanguageTag().lowercase()
401-
listener?.getOpenRouteServiceApi()?.let { api ->
401+
listener?.getOpenRouteServiceClient()?.let { client ->
402402
val profile = sharedPreferences.getString(PREF_ORS_PROFILE, "driving-car")
403403
profile?.let {
404-
val directions = Directions(api, it)
404+
val directions = Directions(client, it)
405405
directions.getRouteGpx(coordinates, language, object : Directions.RouteGpResult {
406406
override fun onSuccess(gpx: String) {
407407
Log.d(TAG, "GPX: $gpx")
@@ -1060,9 +1060,9 @@ class MapFragment : Fragment(), LocationListener, PopupMenu.OnMenuItemClickListe
10601060
fun showPrivacyOptionsForm()
10611061

10621062
/**
1063-
* Get the ORS API if available
1063+
* Get the ORS client if available
10641064
*/
1065-
fun getOpenRouteServiceApi(): OpenRouteServiceApi?
1065+
fun getOpenRouteServiceClient(): OrsClient?
10661066

10671067
/**
10681068
* Parse GPX string

app/src/main/java/org/nitri/opentopo/ors/Directions.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ import kotlinx.coroutines.CoroutineScope
44
import kotlinx.coroutines.Dispatchers
55
import kotlinx.coroutines.launch
66
import kotlinx.coroutines.withContext
7-
import org.nitri.ors.api.OpenRouteServiceApi
8-
import org.nitri.ors.repository.RouteRepository
7+
import org.nitri.ors.OrsClient
8+
import org.nitri.ors.helper.RouteHelper
99

10-
class Directions(val api: OpenRouteServiceApi, private val profile: String) {
10+
class Directions(val client: OrsClient, private val profile: String) {
1111

12-
val repository = RouteRepository(api)
12+
val routeHelper = RouteHelper()
1313

1414
fun getRouteGpx(coordinates: List<List<Double>>, language: String, result: RouteGpResult) {
1515
CoroutineScope(Dispatchers.IO).launch {
1616
try {
17-
val gpxXml = repository.getRouteGpx(coordinates, language, profile)
17+
val gpxXml = with(routeHelper) { client.getRouteGpx(coordinates, language, profile) }
1818
withContext(Dispatchers.Main) {
1919
if (gpxXml.isNotBlank()) {
2020
result.onSuccess(gpxXml)

ors-client/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins {
99

1010
android {
1111
namespace = "org.nitri.ors"
12-
compileSdk = 35
12+
compileSdk = 36
1313

1414
defaultConfig {
1515
minSdk = 24
@@ -42,6 +42,8 @@ android {
4242
lint {
4343
targetSdk = 35
4444
}
45+
46+
publishing { singleVariant("release") { withSourcesJar() } }
4547
}
4648

4749
dependencies {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.nitri.ors
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4
4+
import kotlinx.serialization.json.buildJsonArray
5+
import kotlinx.serialization.json.buildJsonObject
6+
import kotlinx.serialization.json.put
7+
import org.junit.Assert.assertEquals
8+
import org.junit.Assert.assertThrows
9+
import org.junit.Test
10+
import org.junit.runner.RunWith
11+
import org.nitri.ors.domain.elevation.ElevationLineRequestBuilderJ
12+
import org.nitri.ors.domain.elevation.ElevationPointRequestBuilderJ
13+
import org.nitri.ors.domain.elevation.ElevationFormats
14+
import org.nitri.ors.domain.elevation.elevationLineRequest
15+
import org.nitri.ors.domain.elevation.elevationPointRequest
16+
17+
@RunWith(AndroidJUnit4::class)
18+
class ElevationDslInstrumentedTest {
19+
20+
@Test
21+
fun dsl_buildsElevationLine_polyline() {
22+
val req = elevationLineRequest {
23+
polyline(8.681495 to 49.41461, 8.687872 to 49.420318)
24+
formatOut = ElevationFormats.GEOJSON
25+
}
26+
assertEquals(ElevationFormats.POLYLINE, req.formatIn)
27+
assertEquals(ElevationFormats.GEOJSON, req.formatOut)
28+
}
29+
30+
@Test
31+
fun dsl_requires_geometry_for_elevationLine() {
32+
assertThrows(IllegalArgumentException::class.java) {
33+
elevationLineRequest { formatIn = ElevationFormats.POLYLINE }
34+
}
35+
}
36+
37+
@Test
38+
fun dsl_buildsElevationPoint_point() {
39+
val req = elevationPointRequest {
40+
point(8.681495, 49.41461)
41+
formatIn = "point"
42+
formatOut = "geojson"
43+
}
44+
assertEquals("geojson", req.formatOut)
45+
assertEquals("point", req.formatIn)
46+
}
47+
48+
@Test
49+
fun javaBuilder_buildsElevationLine_polyline() {
50+
val req = ElevationLineRequestBuilderJ()
51+
.polyline(listOf(listOf(8.0,48.0), listOf(9.0,49.0)))
52+
.formatOut(ElevationFormats.GEOJSON)
53+
.build()
54+
assertEquals(ElevationFormats.POLYLINE, req.formatIn)
55+
}
56+
57+
@Test
58+
fun javaBuilder_buildsElevationPoint_point() {
59+
val req = ElevationPointRequestBuilderJ()
60+
.point(8.0, 48.0)
61+
.formatOut("geojson")
62+
.build()
63+
assertEquals("geojson", req.formatOut)
64+
}
65+
}

ors-client/src/androidTest/java/org/nitri/ors/ElevationInstrumentedTest.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,28 @@ import org.junit.Assert.assertNotNull
99
import org.junit.Assert.assertTrue
1010
import org.junit.Test
1111
import org.junit.runner.RunWith
12-
import org.nitri.ors.client.OpenRouteServiceClient
13-
import org.nitri.ors.repository.ElevationRepository
12+
import org.nitri.ors.helper.ElevationHelper
1413

1514
@RunWith(AndroidJUnit4::class)
1615
class ElevationInstrumentedTest {
1716

18-
private fun createRepository(context: Context): ElevationRepository {
17+
private fun create(context: Context): Pair<DefaultOrsClient, ElevationHelper> {
1918
val apiKey = context.getString(R.string.ors_api_key)
20-
val api = OpenRouteServiceClient.create(apiKey, context)
21-
return ElevationRepository(api)
19+
val client = DefaultOrsClient(apiKey, context)
20+
val helper = ElevationHelper()
21+
return client to helper
2222
}
2323

2424
@Test
2525
fun testElevation_point_successful() = runBlocking {
2626
val context = ApplicationProvider.getApplicationContext<Context>()
27-
val repository = createRepository(context)
27+
val (client, helper) = create(context)
2828

2929
// A point near Heidelberg, Germany
3030
val lon = 8.681495
3131
val lat = 49.41461
3232

33-
val response = repository.getElevationPoint(lon = lon, lat = lat)
33+
val response = with(helper) { client.getElevationPoint(lon = lon, lat = lat) }
3434

3535
assertNotNull("Elevation point response should not be null", response)
3636
assertNotNull("Geometry should not be null", response.geometry)
@@ -49,15 +49,15 @@ class ElevationInstrumentedTest {
4949
@Test
5050
fun testElevation_line_successful() = runBlocking {
5151
val context = ApplicationProvider.getApplicationContext<Context>()
52-
val repository = createRepository(context)
52+
val (client, helper) = create(context)
5353

5454
// A short line segment around Heidelberg
5555
val coordinates = listOf(
5656
listOf(8.681495, 49.41461),
5757
listOf(8.687872, 49.420318)
5858
)
5959

60-
val response = repository.getElevationLine(coordinates = coordinates)
60+
val response = with(helper) { client.getElevationLine(coordinates = coordinates) }
6161

6262
assertNotNull("Elevation line response should not be null", response)
6363
assertEquals("Geometry type should be LineString", "LineString", response.geometry.type)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.nitri.ors
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4
4+
import org.junit.Assert.assertEquals
5+
import org.junit.Assert.assertThrows
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
import org.nitri.ors.domain.export.ExportRequestBuilderJ
9+
import org.nitri.ors.domain.export.exportRequest
10+
11+
@RunWith(AndroidJUnit4::class)
12+
class ExportDslInstrumentedTest {
13+
14+
@Test
15+
fun dsl_buildsExportRequest_andValidates() {
16+
val req = exportRequest {
17+
bbox(8.681495, 49.41461, 8.686507, 49.41943)
18+
id("test-id")
19+
geometry(true)
20+
}
21+
assertEquals("test-id", req.id)
22+
assertEquals(listOf(listOf(8.681495,49.41461), listOf(8.686507,49.41943)), req.bbox)
23+
}
24+
25+
@Test
26+
fun dsl_requires_bbox() {
27+
assertThrows(IllegalArgumentException::class.java) {
28+
exportRequest { geometry(false) }
29+
}
30+
}
31+
32+
@Test
33+
fun javaBuilder_buildsExportRequest_andValidates() {
34+
val req = ExportRequestBuilderJ()
35+
.bbox(8.0, 48.0, 9.0, 49.0)
36+
.id("jid")
37+
.geometry(null)
38+
.build()
39+
assertEquals("jid", req.id)
40+
assertEquals(listOf(listOf(8.0,48.0), listOf(9.0,49.0)), req.bbox)
41+
}
42+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.nitri.ors
2+
3+
import android.content.Context
4+
import androidx.test.core.app.ApplicationProvider
5+
import androidx.test.ext.junit.runners.AndroidJUnit4
6+
import kotlinx.coroutines.runBlocking
7+
import org.junit.Assert.assertNotNull
8+
import org.junit.Assert.assertTrue
9+
import org.junit.Test
10+
import org.junit.runner.RunWith
11+
import org.nitri.ors.helper.ExportHelper
12+
13+
@RunWith(AndroidJUnit4::class)
14+
class ExportInstrumentedTest {
15+
16+
private fun create(context: Context): Pair<DefaultOrsClient, ExportHelper> {
17+
val apiKey = context.getString(R.string.ors_api_key)
18+
val client = DefaultOrsClient(apiKey, context)
19+
val helper = ExportHelper()
20+
return client to helper
21+
}
22+
23+
@Test
24+
fun testExport_successful() = runBlocking {
25+
val context = ApplicationProvider.getApplicationContext<Context>()
26+
val (client, helper) = create(context)
27+
28+
// Bounding box around Heidelberg, Germany
29+
val bbox = listOf(
30+
listOf(8.681495, 49.41461), // minLon, minLat
31+
listOf(8.686507, 49.41943) // maxLon, maxLat
32+
)
33+
34+
val response = with(helper) { client.export(bbox = bbox, profile = Profile.DRIVING_CAR) }
35+
36+
assertNotNull("Export response should not be null", response)
37+
// Basic sanity checks on structure
38+
assertTrue("Points list should not be empty", response.nodes.isNotEmpty())
39+
assertTrue("Edges list should not be empty", response.edges.isNotEmpty())
40+
}
41+
42+
// Exceeds rate limit
43+
// @Test
44+
// fun testExportJson_successful() = runBlocking {
45+
// val context = ApplicationProvider.getApplicationContext<Context>()
46+
//
47+
// val (client, helper) = create(context)
48+
// val bbox = listOf(
49+
// listOf(8.681495, 49.41461),
50+
// listOf(8.686507, 49.41943)
51+
// )
52+
//
53+
// val response = with(helper) { client.exportJson(bbox = bbox, profile = "driving-car") }
54+
//
55+
// assertNotNull("JSON Export response should not be null", response)
56+
// assertTrue("Points list should not be empty", response.nodes.isNotEmpty())
57+
// }
58+
59+
// Exceeds rate limit
60+
// @Test
61+
// fun testExportTopoJson_successful() = runBlocking {
62+
// val context = ApplicationProvider.getApplicationContext<Context>()
63+
// val (client, helper) = create(context)
64+
//
65+
// val bbox = listOf(
66+
// listOf(8.681495, 49.41461),
67+
// listOf(8.686507, 49.41943)
68+
// )
69+
//
70+
// val topo = with(helper) { client.exportTopoJson(bbox = bbox, profile = "driving-car") }
71+
//
72+
// assertNotNull("TopoJSON Export response should not be null", topo)
73+
// assertTrue("Type should be present", topo.type.isNotBlank())
74+
// }
75+
}

0 commit comments

Comments
 (0)