mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-10-02 16:44:33 -04:00
perf(store-screenshots): wait for the map to draw instead of a fixed 45 seconds (#7501)
This commit is contained in:
1 parent
ee54232a98
commit
0c9d007da9
3 files changed
+42
-4
No files matched your search
@@ -706,7 +706,11 @@ fun MapView(
|
||||
mapType = effectiveGoogleMapType,
|
||||
isMyLocationEnabled = isLocationTrackingEnabled && locationPermission.isGranted,
|
||||
),
|
||||
onMapLoaded = { isMapLoaded = true },
|
||||
onMapLoaded = {
|
||||
isMapLoaded = true
|
||||
// The store-screenshot capture waits for this tag instead of a fixed delay.
|
||||
Logger.withTag("MapDrawn").d { "tiles drawn" }
|
||||
},
|
||||
onMapClick = { latLng ->
|
||||
if (isMainMode && boxAuthoringDraft != null) {
|
||||
val first = boxAuthoringFirstCorner
|
||||
|
||||
+11
@@ -31,8 +31,11 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.dropWhile
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -51,6 +54,7 @@ import org.maplibre.compose.location.updateCamera
|
||||
import org.maplibre.compose.map.CameraConstraints
|
||||
import org.maplibre.compose.map.LocalMapState
|
||||
import org.maplibre.compose.map.LocalViewport
|
||||
import org.maplibre.compose.map.MapEvent
|
||||
import org.maplibre.compose.map.MapState
|
||||
import org.maplibre.compose.map.MaplibreMap
|
||||
import org.maplibre.compose.map.rememberMapState
|
||||
@@ -228,6 +232,13 @@ fun MeshMap(
|
||||
// thrown by the time this is reached.
|
||||
if (!LocalMapLibreRuntimeProbe.current()) return MapEngineUnavailable(modifier)
|
||||
|
||||
// The store-screenshot capture waits for this tag instead of a fixed delay.
|
||||
LaunchedEffect(mapState) {
|
||||
// Idle can arrive before the first render session; only an idle after a drawn frame means tiles are on screen.
|
||||
mapState.events.dropWhile { it !is MapEvent.FrameRendered }.filterIsInstance<MapEvent.Idle>().first()
|
||||
Logger.withTag("MapDrawn").d { "tiles drawn" }
|
||||
}
|
||||
|
||||
val zoomRange = basemap.zoomRange()
|
||||
MaplibreMap(
|
||||
modifier = modifier,
|
||||
|
||||
+26
-3
@@ -132,7 +132,7 @@ class StoreScreenshots {
|
||||
open(Shot.Nodes.path)
|
||||
SystemClock.sleep(READ_WARM_UP_MS)
|
||||
}
|
||||
open(shot.path)
|
||||
if (shot.waitsForMapDrawn) openAndAwaitMapDrawn(shot) else open(shot.path)
|
||||
SystemClock.sleep(shot.minimumWaitMs)
|
||||
val stable =
|
||||
waitForStableInActiveWindow(
|
||||
@@ -150,6 +150,22 @@ class StoreScreenshots {
|
||||
save(bitmap, name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the map to log that its tiles are drawn: Google Maps' onMapLoaded, MapLibre's first idle. The stability
|
||||
* check after it still covers the camera settling on the mesh.
|
||||
*/
|
||||
private fun UiAutomatorTestScope.openAndAwaitMapDrawn(shot: Shot) {
|
||||
// A time boundary, not a line count: logcat is a ring buffer and older matches rotate out.
|
||||
val since = System.currentTimeMillis().let { "%d.%03d".format(it / MILLIS_PER_SECOND, it % MILLIS_PER_SECOND) }
|
||||
open(shot.path)
|
||||
val deadline = SystemClock.uptimeMillis() + MAP_DRAWN_TIMEOUT_MS
|
||||
while (SystemClock.uptimeMillis() < deadline) {
|
||||
if (MAP_DRAWN_MESSAGE in shell("logcat -d -T $since -s $MAP_DRAWN_TAG")) return
|
||||
SystemClock.sleep(POLL_MS)
|
||||
}
|
||||
Log.w(TAG, "${shot.fileName} never logged $MAP_DRAWN_TAG; capturing after the timeout")
|
||||
}
|
||||
|
||||
/** Launches through the debug build's shell-only alias, the one launch the app honours the switches on. */
|
||||
private fun UiAutomatorTestScope.open(path: String, clearTask: Boolean = false) {
|
||||
val flags = if (clearTask) "--activity-clear-task " else ""
|
||||
@@ -189,7 +205,7 @@ class StoreScreenshots {
|
||||
TenInch("tenInchScreenshots", 2560, 1440, 320),
|
||||
}
|
||||
|
||||
/** The five listing shots, named as fastlane lays them out. The map loads tiles for a while before it settles. */
|
||||
/** The five listing shots, named as fastlane lays them out. The map waits for its tiles before it settles. */
|
||||
private enum class Shot(
|
||||
val fileName: String,
|
||||
val path: String,
|
||||
@@ -197,11 +213,12 @@ class StoreScreenshots {
|
||||
val stableTimeoutMs: Long = 30_000,
|
||||
val stableIntervalMs: Long = 2_000,
|
||||
val readFirst: Boolean = false,
|
||||
val waitsForMapDrawn: Boolean = false,
|
||||
) {
|
||||
// The primary channel's contact key, raw: `am start` takes it literally and Uri.parse accepts the caret.
|
||||
Messages("1_messages", "messages/0^all", readFirst = true),
|
||||
Nodes("2_nodes", "nodes"),
|
||||
Map("3_map", "map", minimumWaitMs = 45_000, stableTimeoutMs = 120_000, stableIntervalMs = 8_000),
|
||||
Map("3_map", "map", stableTimeoutMs = 120_000, stableIntervalMs = 8_000, waitsForMapDrawn = true),
|
||||
NodeDetail("4_node_detail", "nodes/$RIDGE_TOP_NUM"),
|
||||
Channels("5_channels", "channels"),
|
||||
}
|
||||
@@ -230,6 +247,12 @@ class StoreScreenshots {
|
||||
|
||||
const val READ_WARM_UP_MS = 3_000L
|
||||
|
||||
/** Logged by both flavors' maps (MapView.kt, MeshMap.kt) once the tiles are drawn. */
|
||||
const val MAP_DRAWN_TAG = "MapDrawn"
|
||||
const val MAP_DRAWN_MESSAGE = "tiles drawn"
|
||||
const val MAP_DRAWN_TIMEOUT_MS = 45_000L
|
||||
const val MILLIS_PER_SECOND = 1_000L
|
||||
|
||||
const val CONNECT_ATTEMPTS = 3
|
||||
const val CONNECT_TIMEOUT_MS = 60_000L
|
||||
const val POLL_MS = 500L
|
||||
|
||||
Reference in new issue
Block a user