ReviewOS

also looking at this

craft-native/craft

feat(maps): add key-free native Android maps and shared map controls

#363
Merged chris wants to merge codex/wildloop-native-map-providers into main
28 files +1857 -481

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/android/fixtures/native-navigation/NativeMapTest.ktmodified+33-2
Changes to packages/android/fixtures/native-navigation/NativeMapTest.kt
@@ -73,6 +73,31 @@ class NativeMapTest {
7373 image.recycle()
7474 }
7575
76 private fun awaitBasemapPixels(host: CraftNativeMapView, label: String) {
77 val deadline = SystemClock.uptimeMillis() + 45_000
78 do {
79 val bounds = main {
80 val origin = IntArray(2).also { host.getLocationOnScreen(it) }
81 intArrayOf(origin[0], origin[1], host.width, host.height)
82 }
83 val image = instrumentation.uiAutomation.takeScreenshot() ?: throw AssertionError("Native screenshot unavailable")
84 val visible = try {
85 // Sample across the map, away from controls/credits and the thin
86 // route. A rendered overlay over an empty black surface fails.
87 var painted = 0
88 for (row in 1..8) for (column in 1..8) {
89 val pixel = image.getPixel(bounds[0] + bounds[2] * column / 9, bounds[1] + bounds[3] * row / 9)
90 if (Color.red(pixel) + Color.green(pixel) + Color.blue(pixel) > 60) painted++
91 }
92 painted >= 58
93 } finally { image.recycle() }
94 if (visible) return
95 SystemClock.sleep(100)
96 } while (SystemClock.uptimeMillis() < deadline)
97 evidence("$label-basemap-not-visible")
98 fail("$label did not paint native basemap tiles across the viewport")
99 }
100
76101 private fun withMap(block: (MainActivity, CraftNativeMapView, MapView, MapLibreMap, AtomicInteger) -> Unit) {
77102 val activity = instrumentation.startActivitySync(Intent(instrumentation.targetContext, MainActivity::class.java)
78103 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)) as MainActivity
@@ -104,10 +129,13 @@ class NativeMapTest {
104129 }
105130
106131 @Test
107 fun keyFreeBasemapsKeepTheRecordedRouteAndDirectionSignsVisible() = withMap { _, host, _, map, loaded ->
132 fun keyFreeBasemapsKeepTheRecordedRouteAndDirectionSignsVisible() = withMap { _, host, widget, map, loaded ->
108133 for (type in listOf("outdoors", "standard", "satellite", "hybrid")) {
109134 val before = loaded.get()
135 val rendered = AtomicInteger()
136 val listener = MapView.OnDidFinishRenderingFrameListener { fully, _, _ -> if (fully) rendered.incrementAndGet() }
110137 main {
138 widget.addOnDidFinishRenderingFrameListener(listener)
111139 val options = props().put("mapType", if (type == "outdoors") "standard" else type)
112140 if (type == "outdoors") options.put("tileOverlay", JSONObject()
113141 .put("urlTemplate", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}")
@@ -115,9 +143,11 @@ class NativeMapTest {
115143 host.configure(options, overlays()) {}
116144 }
117145 awaitState("$type did not finish loading its real native basemap") {
118 loaded.get() > before && features(map).size == 3 &&
146 loaded.get() > before && rendered.get() > 0 && features(map).size == 3 &&
119147 map.queryRenderedFeatures(map.projection.toScreenLocation(LatLng(47.005, 11.005)), "craft-map-directions").isNotEmpty()
120148 }
149 awaitBasemapPixels(host, type)
150 main { widget.removeOnDidFinishRenderingFrameListener(listener) }
121151 main {
122152 val start = features(map).first { it.getStringProperty("craftOverlayId") == "start" }.geometry() as Point
123153 assertEquals(47.0, start.latitude(), 0.000001)
@@ -145,6 +175,7 @@ class NativeMapTest {
145175 kotlin.math.abs(map.cameraPosition.bearing - 90) < 1 && kotlin.math.abs(map.cameraPosition.tilt - 30) < 1 &&
146176 map.queryRenderedFeatures(map.projection.toScreenLocation(LatLng(47.0, 11.0)), "craft-map-markers").any { it.getStringProperty("color") == "rgba(40,120,200,1.0)" }
147177 }
178 awaitBasemapPixels(host, "mutated-map")
148179 main {
149180 assertSame("Overlay updates must not reload the native basemap", style, map.style)
150181 assertTrue(map.uiSettings.isTiltGesturesEnabled)