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+26-12
Changes to packages/android/fixtures/native-navigation/NativeMapTest.kt
@@ -186,21 +186,35 @@ class NativeMapTest {
186186 assertEquals(3, features(map).size)
187187 }
188188 // Inspect the actual rendered pin, not just the JSON property sent to GL.
189 val location = main {
190 val screen = map.projection.toScreenLocation(LatLng(47.0, 11.0))
191 val origin = IntArray(2).also { host.getLocationOnScreen(it) }
192 (screen.x.toInt() + origin[0]) to (screen.y.toInt() + origin[1])
189 // A native source query can observe new feature properties before the
190 // compositor presents that frame. Require the actual requested color,
191 // using a fresh projection for each capture while the camera settles.
192 val deadline = SystemClock.uptimeMillis() + 45_000
193 var location: Pair<Int, Int>? = null
194 var lastPixel = Color.TRANSPARENT
195 while (SystemClock.uptimeMillis() < deadline && location == null) {
196 val candidate = main {
197 val screen = map.projection.toScreenLocation(LatLng(47.0, 11.0))
198 val origin = IntArray(2).also { host.getLocationOnScreen(it) }
199 (screen.x.toInt() + origin[0]) to (screen.y.toInt() + origin[1])
200 }
201 val image = instrumentation.uiAutomation.takeScreenshot() ?: throw AssertionError("Native screenshot unavailable")
202 try {
203 lastPixel = image.getPixel(candidate.first, candidate.second)
204 if (kotlin.math.abs(Color.red(lastPixel) - 40) <= 8 &&
205 kotlin.math.abs(Color.green(lastPixel) - 120) <= 8 &&
206 kotlin.math.abs(Color.blue(lastPixel) - 200) <= 8) location = candidate
207 } finally { image.recycle() }
208 if (location == null) SystemClock.sleep(100)
193209 }
194 val image = instrumentation.uiAutomation.takeScreenshot() ?: throw AssertionError("Native screenshot unavailable")
195 try {
196 val pixel = image.getPixel(location.first, location.second)
197 assertEquals(40.0, Color.red(pixel).toDouble(), 8.0)
198 assertEquals(120.0, Color.green(pixel).toDouble(), 8.0)
199 assertEquals(200.0, Color.blue(pixel).toDouble(), 8.0)
200 } finally { image.recycle() }
210 if (location == null) evidence("map-mutated-pin-not-visible")
211 assertEquals("The compositor must show the new pin red channel", 40.0, Color.red(lastPixel).toDouble(), 8.0)
212 assertEquals("The compositor must show the new pin green channel", 120.0, Color.green(lastPixel).toDouble(), 8.0)
213 assertEquals("The compositor must show the new pin blue channel", 200.0, Color.blue(lastPixel).toDouble(), 8.0)
214 val tap = location ?: throw AssertionError("The updated native pin was never visible")
201215 val downAt = SystemClock.uptimeMillis()
202216 for (action in listOf(android.view.MotionEvent.ACTION_DOWN, android.view.MotionEvent.ACTION_UP)) {
203 val touch = android.view.MotionEvent.obtain(downAt, SystemClock.uptimeMillis(), action, location.first.toFloat(), location.second.toFloat(), 0)
217 val touch = android.view.MotionEvent.obtain(downAt, SystemClock.uptimeMillis(), action, tap.first.toFloat(), tap.second.toFloat(), 0)
204218 try { assertTrue(instrumentation.uiAutomation.injectInputEvent(touch, true)) } finally { touch.recycle() }
205219 }
206220 awaitState("Tapping the actual native pin must dispatch its stable marker ID") { pressed.get() == "start" }