Merges to keep up to date with v1.0 and test fixes - #965
Merged
Conversation
We moved the multiplatform branch to main and so we needed to rejig.
Ignoring the safe mode resulted in parts of the screen being drawn behind camera slots etc.
TextToSpeech.getVoices() makes a synchronous Binder IPC to the system TTS service, which can block for a long time on some OEM builds. It was being called from viewModelScope's default Main dispatcher, blocking the UI thread and triggering ANRs. Move it and getAvailableSpeechEngines() to Dispatchers.IO. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rror callback Calling release() synchronously from within OnCompletionListener/OnErrorListener re-enters MediaPlayer's native teardown while its EventHandler is still dispatching that very callback, which can hang the main thread waiting on native locks. Posting the release to the next message-loop iteration breaks the reentrancy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Our own worst-case splash hold time (maxSplashDelay=7000ms) exceeded Android's 5s "no focused window" input-dispatch ANR timeout, so a tap during a slow/never-completing splash sound could outlast the system's patience for the window to become focusable. Cuts the safety net to 3000ms, comfortably under that threshold. Also replaces the hand-rolled ViewTreeObserver.OnPreDrawListener that held the splash open by suppressing the content view's first draw with the platform's own SplashScreen.setKeepOnScreenCondition/ setOnExitAnimationListener APIs, which are coordinated with WindowManagerService's window-focus bookkeeping rather than working around it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TileSearch only ever resolved fuzzy hits back to a feature via the literal "name" tag, so POIs whose matching text lived under name:hi, name:pa etc. (very common in OSM/OpenMapTiles data) were found by the fuzzy pass but silently dropped during feature resolution, leaving non-English searches (e.g. Hindi) empty. Also surface the actual matched name variant instead of always re-reading the Latin "name" tag, and stop normalizeForSearch from stripping non-Latin combining marks (Devanagari matras/virama etc.) that it was only meant to strip for Latin/Greek/Cyrillic accents. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Photon server only supports en/fr/de + each location's local language, and getPhotonLanguage() already correctly omits the lang param for anything else so Photon falls back to local-language matching - verified this against the live production server for an Arabic query. There was no test coverage for this behavior at all, so add a fast unit test for the fallback logic plus an instrumented end-to-end check against the real server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bring in ANR fixes (splash input dispatch, MediaPlayer.release in callback, TTS getVoices binder call), offline search fixes for localized POI names, and doc/version updates from v1.0. # Conflicts: # app/build.gradle.kts # app/src/androidTest/java/org/scottishtecharmy/soundscape/GeocoderTest.kt # app/src/main/java/org/scottishtecharmy/soundscape/MainActivity.kt # app/src/main/java/org/scottishtecharmy/soundscape/viewmodels/SettingsViewModel.kt # app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt # docs/documentationScreens/homeScreen.png # docs/documentationScreens/homeScreenWithRoute.png # docs/documentationScreens/routeDetails.png # docs/documentationScreens/routeEdit.png # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/geoengine/utils/geocoders/TileSearch.kt
The main change here is removing the audio beacons being a scrolling list within the screen and instead just having the screen be bigger an containing the whole list. This makes Maestro tests much easier as swipping upwards works the same at any point on the screen. Rows had been split into separate beacon+icon by mistake at some point. That's fixed.
# Conflicts: # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/onboarding/audiobeacons/AudioBeaconItem.kt # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/onboarding/audiobeacons/AudioBeacons.kt
TileSearch only ever resolved fuzzy hits back to a feature via the literal "name" tag, so POIs whose matching text lived under name:hi, name:pa etc. (very common in OSM/OpenMapTiles data) were found by the fuzzy pass but silently dropped during feature resolution, leaving non-English searches (e.g. Hindi) empty. Also surface the actual matched name variant instead of always re-reading the Latin "name" tag, and stop normalizeForSearch from stripping non-Latin combining marks (Devanagari matras/virama etc.) that it was only meant to strip for Latin/Greek/Cyrillic accents. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Photon server only supports en/fr/de + each location's local language, and getPhotonLanguage() already correctly omits the lang param for anything else so Photon falls back to local-language matching - verified this against the live production server for an Arabic query. There was no test coverage for this behavior at all, so add a fast unit test for the fallback logic plus an instrumented end-to-end check against the real server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The main change here is removing the audio beacons being a scrolling list within the screen and instead just having the screen be bigger an containing the whole list. This makes Maestro tests much easier as swipping upwards works the same at any point on the screen. Rows had been split into separate beacon+icon by mistake at some point. That's fixed.
StreetDescription.getInterpolateLocation() assumed every house number feature had Point geometry, but building/POI polygons tagged with a housenumber also get added to the street's house number map. Use getCentralPointForFeature() (already used elsewhere for this) instead of casting directly to Point. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # app/build.gradle.kts # app/src/androidTest/java/org/scottishtecharmy/soundscape/GeocoderTest.kt # app/src/test/java/org/scottishtecharmy/soundscape/GeoEngineLanguageTest.kt # app/src/test/java/org/scottishtecharmy/soundscape/SearchTest.kt # docs/documentationScreens/homeScreen.png # docs/documentationScreens/homeScreenWithRoute.png # docs/documentationScreens/routeDetails.png # docs/documentationScreens/routeEdit.png # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/geoengine/utils/geocoders/StreetDescription.kt # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/geoengine/utils/geocoders/TileSearch.kt # shared/src/commonMain/kotlin/org/scottishtecharmy/soundscape/screens/onboarding/audiobeacons/AudioBeacons.kt
AGP 9.2+ throws a ClassCastException on shared/'s classic
com.android.library + androidTarget() setup (sourceSets["main"] no
longer casts to AndroidLibrarySourceSet). Migrate shared/ to AGP 9's
native com.android.kotlin.multiplatform.library plugin with
kotlin.androidLibrary{}, matching the pattern already used by the
ComposePreference/preference submodule.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…anded protobuf-gradle-plugin 0.10.0 and KSP 2.3.10 both added AGP 9 support since these flags were added. Also needed: bump com.jaredsburrows.license 0.9.8 -> 0.9.9 (was calling into the legacy AppExtension type removed by android.newDsl's new default), and drop the now-redundant org.jetbrains.kotlin.android plugin from app/ (AGP 9's built-in Kotlin support refuses to coexist with it). Regenerates open_source_licenses.json, which is more complete than before (262 -> 333 entries). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumps ~30 patch/minor dependencies plus three deliberate major-version jumps (Wire, reorderable, JUnit Jupiter) and compose-bom. MapLibre and kable are capped below their latest releases - see inline comments in libs.versions.toml for why (MapLibre 13.4.0+ statically links its STL, conflicting with this app's own native code; kable 0.43.1+ requires a newer Kotlin KLIB ABI than this project's Kotlin version supports). Also removes 10 unused libraries, 8 orphaned version keys, and 2 unused plugins (kotlin-serialization, google-protobuf - the latter was never actually applied anywhere; Wire already handles this project's protobuf codegen for vector tiles). shared's compileSdk bumped 36 -> 37 to satisfy lifecycle-viewmodel-compose-android 2.11.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… version The patch was pinning the submodule's android-gradlePlugin to 9.0.1 to match what root used to be pinned to, before this session's AGP migration bumped root to 9.3.0. On a fresh checkout the patch reapplies unconditionally, so CI hit "Using multiple versions of the Android Gradle plugin (9.0.1, 9.3.0) in the same build is not allowed" resolving me.zhanghai.compose.preference:preference. Locally this was masked because the submodule's .patched marker already existed, so the patch never re-ran. Regenerated the patch to upgrade the submodule's AGP to 9.3.0 instead. Also drops the now-unnecessary kotlin downgrade hunk, since the submodule's own upstream default (2.3.10) already matches root. Verified: git apply --check passes, simulated a fresh checkout by deleting .patched and resyncing, and directly resolved :app:debugScreenshotTestCompileClasspath to confirm the dependency substitution now works. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Root cause: maplibre-compose#726 (upstream, still open) - MapLibre's
native multi-touch gesture detector and Compose's own scroll gesture
detection both race for the same touch stream on Android, causing
MotionEvents to get dropped/misrouted between them ("Some MotionEvents
were not passed to the library or events from different view trees are
merged").
Add an onInteractionChanged callback to MapContainerLibre (threaded
through PlatformMapContainer's expect/actual) that fires only on
genuine multi-touch (2+ pointers) over the map. The five screens that
embed the map inline inside a scrollable container use this to disable
that container's scrolling for the duration of the gesture, so only
one system owns the touch stream at a time. Single-finger drags are
deliberately excluded - the map's own pan is already off
(GestureOptions.ZoomOnly), so those fall through to the parent scroll
as before.
Verified pinch-to-zoom on a physical device; confirmed no regression to
single-finger scroll-through or map panning.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real API migrations:
- TabRow -> PrimaryTabRow (SharedNavGraph.kt)
- invisibleToUser() -> hideFromAccessibility() (3 call sites)
- MarkdownParser/buildMarkdownTreeFromString -> non-deprecated
CancellationToken/CharSequence overloads
- Locale(String) -> Locale.forLanguageTag(String) - the input is always
a BCP-47 tag (getCurrentLocale().toLanguageTag())
- launch(context: Job) anti-pattern -> capture the Job launch() returns
instead of pre-creating one and passing it in (2 call sites) - passing
a Job breaks structured concurrency
- resourceConfigurations -> androidResources.localeFilters
- Compose Multiplatform compose.* accessors -> explicit version-catalog
entries (materialIconsExtended stays pinned at 1.7.3 upstream; full
migration to Material Symbols is a separate, larger effort)
- shared/build.gradle.kts: androidLibrary {} -> android {}. Empirically
re-verified given this reverses an earlier finding this session -
full clean build (Android + iOS + tests) confirms android {} is
correct now and the deprecation warning is gone.
Deliberately not migrated: BackHandler -> NavigationEventHandler is
suppressed rather than migrated, since current Compose Multiplatform
only wires the dispatcher BackHandler needs internally - migrating can
break back handling on iOS, which this app targets.
Real gap found via the commonTest warning, not just cosmetic: the 8
test files in shared/src/commonTest (66 tests) were only ever compiled
in CI, never executed - no Android host test task existed, and the
iOS CI job only compiles its test target. Added withHostTest {} to
shared's android {} block, verified all 66 tests pass on first real
run, and updated run-tests.yaml to invoke :shared:testAndroidHostTest
so CI actually exercises them going forward.
Also silences two CI-environment-only warnings: disabled Kotlin/Native
targets on Linux runners (expected, not an error) and the
enableScreenshotTest experimental-flag notice.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Listening onboarding screen's content lives in a verticalScroll container. On CI's smaller emulator profile, "Continue" (at the bottom) can end up scrolled out of the viewport, failing assertIsDisplayed() even though the node exists - it's just not currently visible. Reproduced by comparing against a physical device (passes there) vs the CI failure log. Scroll each node into view via performScrollTo() before asserting, which is a no-op when already visible. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
davecraig
added a commit
to davecraig/Soundscape-AndroidTest
that referenced
this pull request
Aug 1, 2026
…y#965) * Update docs on branches and github actions We moved the multiplatform branch to main and so we needed to rejig. * More docs updating for branch changes * Reinstate safe mode for iOS screens Ignoring the safe mode resulted in parts of the screen being drawn behind camera slots etc. * Debugging iOS runner * Bump version to 1.1.2, version code 204 * New documentation screenshots * Fix main-thread ANR from TTS getVoices() binder call TextToSpeech.getVoices() makes a synchronous Binder IPC to the system TTS service, which can block for a long time on some OEM builds. It was being called from viewModelScope's default Main dispatcher, blocking the UI thread and triggering ANRs. Move it and getAvailableSpeechEngines() to Dispatchers.IO. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix ANR from MediaPlayer.release() called inside its own completion/error callback Calling release() synchronously from within OnCompletionListener/OnErrorListener re-enters MediaPlayer's native teardown while its EventHandler is still dispatching that very callback, which can hang the main thread waiting on native locks. Posting the release to the next message-loop iteration breaks the reentrancy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix ANR: "Input dispatching timed out (No focused window)" during splash Our own worst-case splash hold time (maxSplashDelay=7000ms) exceeded Android's 5s "no focused window" input-dispatch ANR timeout, so a tap during a slow/never-completing splash sound could outlast the system's patience for the window to become focusable. Cuts the safety net to 3000ms, comfortably under that threshold. Also replaces the hand-rolled ViewTreeObserver.OnPreDrawListener that held the splash open by suppressing the content view's first draw with the platform's own SplashScreen.setKeepOnScreenCondition/ setOnExitAnimationListener APIs, which are coordinated with WindowManagerService's window-focus bookkeeping rather than working around it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Bump version to 1.1.3, version code 205 * New documentation screenshots * Fix offline search for localized (name:xx) POI names TileSearch only ever resolved fuzzy hits back to a feature via the literal "name" tag, so POIs whose matching text lived under name:hi, name:pa etc. (very common in OSM/OpenMapTiles data) were found by the fuzzy pass but silently dropped during feature resolution, leaving non-English searches (e.g. Hindi) empty. Also surface the actual matched name variant instead of always re-reading the Latin "name" tag, and stop normalizeForSearch from stripping non-Latin combining marks (Devanagari matras/virama etc.) that it was only meant to strip for Latin/Greek/Cyrillic accents. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add test coverage for Photon search language fallback (Arabic etc.) The Photon server only supports en/fr/de + each location's local language, and getPhotonLanguage() already correctly omits the lang param for anything else so Photon falls back to local-language matching - verified this against the live production server for an Arabic query. There was no test coverage for this behavior at all, so add a fast unit test for the fallback logic plus an instrumented end-to-end check against the real server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Improve audio beacons onboarding screen The main change here is removing the audio beacons being a scrolling list within the screen and instead just having the screen be bigger an containing the whole list. This makes Maestro tests much easier as swipping upwards works the same at any point on the screen. Rows had been split into separate beacon+icon by mistake at some point. That's fixed. * Fix offline search for localized (name:xx) POI names TileSearch only ever resolved fuzzy hits back to a feature via the literal "name" tag, so POIs whose matching text lived under name:hi, name:pa etc. (very common in OSM/OpenMapTiles data) were found by the fuzzy pass but silently dropped during feature resolution, leaving non-English searches (e.g. Hindi) empty. Also surface the actual matched name variant instead of always re-reading the Latin "name" tag, and stop normalizeForSearch from stripping non-Latin combining marks (Devanagari matras/virama etc.) that it was only meant to strip for Latin/Greek/Cyrillic accents. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add test coverage for Photon search language fallback (Arabic etc.) The Photon server only supports en/fr/de + each location's local language, and getPhotonLanguage() already correctly omits the lang param for anything else so Photon falls back to local-language matching - verified this against the live production server for an Arabic query. There was no test coverage for this behavior at all, so add a fast unit test for the fallback logic plus an instrumented end-to-end check against the real server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Improve audio beacons onboarding screen The main change here is removing the audio beacons being a scrolling list within the screen and instead just having the screen be bigger an containing the whole list. This makes Maestro tests much easier as swipping upwards works the same at any point on the screen. Rows had been split into separate beacon+icon by mistake at some point. That's fixed. * Bump version to 1.1.4, version code 206 * New documentation screenshots * Bump version to 1.1.5, version code 207 * Fix ClassCastException when interpolating polygon-geometry house numbers StreetDescription.getInterpolateLocation() assumed every house number feature had Point geometry, but building/POI polygons tagged with a housenumber also get added to the street's house number map. Use getCentralPointForFeature() (already used elsewhere for this) instead of casting directly to Point. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Bump version to 1.1.6, version code 208 * New documentation screenshots * Bump compileSdk and targetSdk to 37 * Bump version to 1.1.7, version code 209 * New documentation screenshots * Give each offline map download a unique filename to avoid a MapLibre native crash MapLibre's native PMTilesFileSource caches parsed header/directory data per pmtiles://file://<path> URL for as long as the process runs, with no API to invalidate it (platform/default/src/mbgl/storage/pmtiles_file_source.cpp in maplibre-native - header_cache, metadata_cache, directory_cache are all keyed by URL and never evicted). The previous OfflineDownloader re-downloaded ("Update") an extract straight over its existing filename, so once a live map had opened that URL, the next tile request read new bytes through offsets cached from the old file - misreading garbage, failing to decompress, and aborting the whole process with no try/catch on MapLibre's worker thread. This crashed in production on release 1.1.7. Fixed by downloading each extract to a versioned filename ("<region>.v<timestamp>.pmtiles") instead of overwriting the existing one, so a re-download never reuses a URL MapLibre has cached anything for. OfflineDownloader deletes the superseded version's .pmtiles file and .geojson sidecar once the new one is published and validated - safe to do immediately, since a reader either still has the old file open (POSIX keeps it readable) or gets a clean "not found" on a fresh open, both already handled gracefully by MapLibre, unlike reading wrong-but-present bytes. delete() now matches on the region's logical basename (anchored on the following '.') so it still removes every version of an extract, including ones downloaded before this change. Also drops the redundant finalFile.delete() before the final rename - harmless either way now that the destination path is always new, but one less non-atomic step. PmtilesSwapCrashTest reproduces the original crash directly (confirmed against a real emulator - SIGABRT in mbgl::util::decompress on the PMTilesFileSource worker thread, "incorrect header check") and is @ignore'd by default since a deliberate process crash can't be expressed as a JUnit assertion; see its KDoc for how to run it manually. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Refresh the geoengine's tile grid immediately when offline maps change Previously a newly downloaded (or deleted) offline map extract was only picked up by ProtomapsGridState's next checkOfflineMaps() call, which itself only runs when the user's location moves outside the current grid's central area - so a completed download or deletion had no effect until the user happened to walk far enough. GridState now exposes refreshOfflineMaps(), which forces the next location update to recompute the grid regardless of movement; this is wired through GeoEngine, SoundscapeService and SoundscapeServiceConnection and called from OfflineMapsViewModel whenever a download succeeds or an extract is deleted, so both the main grid and the settlement grid start using (or stop using) the affected extract within about a second. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Discard offline search's cached tile strings when offline maps change TileSearch.stringCache caches each tile's normalized search strings keyed only by tile (x, y), independent of which extract the data was read from. Since the search spiral re-visits the same tiles on repeat searches near the same location, a superseded or deleted extract's strings for those tiles were never evicted, so search results could stay stale indefinitely after an offline map was replaced or removed. refreshOfflineMaps() now clears this cache too, wired in alongside the grid refresh already triggered when a download succeeds or an extract is deleted. stringCache is now a ConcurrentHashMap since it can be cleared from a different thread than an in-progress search() call. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Increase photon client timeout to 10 seconds I was seeing Search timeout with the previous 5 seconds setting, so increase it to 10. * Retry adb root in Maestro CI to survive intermittent adbd restart race adb root occasionally fails with "unable to connect for root: closed" right after the emulator boots, which was killing the whole matrix leg since each script line runs in its own shell. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Widen Maestro launch-retry to catch device-offline adbd race launchApp's own adb call can hit the same adbd-restart race already retried for adb root, but it surfaces as "device offline" instead of "Unable to launch app" - the rf() helper's grep only matched the latter, so this failure mode skipped the retry and failed the whole run on the first flow (seen consistently on API 36 + small_phone + en-US). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Bump Gradle version to support SDK 37 * Bump AGP to 9.3.0, Gradle to 9.6.1, Kotlin to 2.3.10 AGP 9.2+ throws a ClassCastException on shared/'s classic com.android.library + androidTarget() setup (sourceSets["main"] no longer casts to AndroidLibrarySourceSet). Migrate shared/ to AGP 9's native com.android.kotlin.multiplatform.library plugin with kotlin.androidLibrary{}, matching the pattern already used by the ComposePreference/preference submodule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Drop android.newDsl/builtInKotlin workarounds now AGP 9 support has landed protobuf-gradle-plugin 0.10.0 and KSP 2.3.10 both added AGP 9 support since these flags were added. Also needed: bump com.jaredsburrows.license 0.9.8 -> 0.9.9 (was calling into the legacy AppExtension type removed by android.newDsl's new default), and drop the now-redundant org.jetbrains.kotlin.android plugin from app/ (AGP 9's built-in Kotlin support refuses to coexist with it). Regenerates open_source_licenses.json, which is more complete than before (262 -> 333 entries). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Bump straightforward dependencies, remove unused version catalog entries Bumps ~30 patch/minor dependencies plus three deliberate major-version jumps (Wire, reorderable, JUnit Jupiter) and compose-bom. MapLibre and kable are capped below their latest releases - see inline comments in libs.versions.toml for why (MapLibre 13.4.0+ statically links its STL, conflicting with this app's own native code; kable 0.43.1+ requires a newer Kotlin KLIB ABI than this project's Kotlin version supports). Also removes 10 unused libraries, 8 orphaned version keys, and 2 unused plugins (kotlin-serialization, google-protobuf - the latter was never actually applied anywhere; Wire already handles this project's protobuf codegen for vector tiles). shared's compileSdk bumped 36 -> 37 to satisfy lifecycle-viewmodel-compose-android 2.11.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix stale ComposePreference patch downgrading AGP below root's pinned version The patch was pinning the submodule's android-gradlePlugin to 9.0.1 to match what root used to be pinned to, before this session's AGP migration bumped root to 9.3.0. On a fresh checkout the patch reapplies unconditionally, so CI hit "Using multiple versions of the Android Gradle plugin (9.0.1, 9.3.0) in the same build is not allowed" resolving me.zhanghai.compose.preference:preference. Locally this was masked because the submodule's .patched marker already existed, so the patch never re-ran. Regenerated the patch to upgrade the submodule's AGP to 9.3.0 instead. Also drops the now-unnecessary kotlin downgrade hunk, since the submodule's own upstream default (2.3.10) already matches root. Verified: git apply --check passes, simulated a fresh checkout by deleting .patched and resyncing, and directly resolved :app:debugScreenshotTestCompileClasspath to confirm the dependency substitution now works. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix unreliable pinch-to-zoom on maps embedded in scrollable screens Root cause: maplibre-compose#726 (upstream, still open) - MapLibre's native multi-touch gesture detector and Compose's own scroll gesture detection both race for the same touch stream on Android, causing MotionEvents to get dropped/misrouted between them ("Some MotionEvents were not passed to the library or events from different view trees are merged"). Add an onInteractionChanged callback to MapContainerLibre (threaded through PlatformMapContainer's expect/actual) that fires only on genuine multi-touch (2+ pointers) over the map. The five screens that embed the map inline inside a scrollable container use this to disable that container's scrolling for the duration of the gesture, so only one system owns the touch stream at a time. Single-finger drags are deliberately excluded - the map's own pan is already off (GestureOptions.ZoomOnly), so those fall through to the parent scroll as before. Verified pinch-to-zoom on a physical device; confirmed no regression to single-finger scroll-through or map panning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix deprecation warnings from the screenshot test build Real API migrations: - TabRow -> PrimaryTabRow (SharedNavGraph.kt) - invisibleToUser() -> hideFromAccessibility() (3 call sites) - MarkdownParser/buildMarkdownTreeFromString -> non-deprecated CancellationToken/CharSequence overloads - Locale(String) -> Locale.forLanguageTag(String) - the input is always a BCP-47 tag (getCurrentLocale().toLanguageTag()) - launch(context: Job) anti-pattern -> capture the Job launch() returns instead of pre-creating one and passing it in (2 call sites) - passing a Job breaks structured concurrency - resourceConfigurations -> androidResources.localeFilters - Compose Multiplatform compose.* accessors -> explicit version-catalog entries (materialIconsExtended stays pinned at 1.7.3 upstream; full migration to Material Symbols is a separate, larger effort) - shared/build.gradle.kts: androidLibrary {} -> android {}. Empirically re-verified given this reverses an earlier finding this session - full clean build (Android + iOS + tests) confirms android {} is correct now and the deprecation warning is gone. Deliberately not migrated: BackHandler -> NavigationEventHandler is suppressed rather than migrated, since current Compose Multiplatform only wires the dispatcher BackHandler needs internally - migrating can break back handling on iOS, which this app targets. Real gap found via the commonTest warning, not just cosmetic: the 8 test files in shared/src/commonTest (66 tests) were only ever compiled in CI, never executed - no Android host test task existed, and the iOS CI job only compiles its test target. Added withHostTest {} to shared's android {} block, verified all 66 tests pass on first real run, and updated run-tests.yaml to invoke :shared:testAndroidHostTest so CI actually exercises them going forward. Also silences two CI-environment-only warnings: disabled Kotlin/Native targets on Linux runners (expected, not an error) and the enableScreenshotTest experimental-flag notice. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix flaky ListeningScreenTest on small-screen CI emulators The Listening onboarding screen's content lives in a verticalScroll container. On CI's smaller emulator profile, "Continue" (at the bottom) can end up scrolled out of the viewport, failing assertIsDisplayed() even though the node exists - it's just not currently visible. Reproduced by comparing against a physical device (passes there) vs the CI failure log. Scroll each node into view via performScrollTo() before asserting, which is a no-op when already visible. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: davecraig <8530624+davecraig@users.noreply.github.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.