From 6204c427fb2b65ff8ed47479f1d0d9bdf65a84bf Mon Sep 17 00:00:00 2001 From: Dale Hawkins <107309+dkhawk@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:04:57 -0600 Subject: [PATCH] fix: check trim memory level in onTrimMemory() implementations Add a level >= TRIM_MEMORY_UI_HIDDEN check in GoogleMap and StreetView onTrimMemory() implementations to avoid unexpectedly trimming needed resources when TRIM_MEMORY_RUNNING_* levels are sent. --- .../google/maps/android/compose/GoogleMap.kt | 34 +++++++++-------- .../android/compose/streetview/StreetView.kt | 6 ++- .../android/compose/MapApplierCleanupTest.kt | 38 +++++++++++++++++++ 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt b/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt index 1951fa27..552852c1 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt @@ -197,21 +197,7 @@ public fun GoogleMap( mapView.setViewTreeLifecycleOwner(lifecycleOwner) mapView.setViewTreeSavedStateRegistryOwner(savedStateRegistryOwner) - val componentCallbacks = object : ComponentCallbacks2 { - override fun onConfigurationChanged(newConfig: Configuration) {} - - @Deprecated( - "Deprecated in Java", - ReplaceWith("onTrimMemory(level)"), - ) - override fun onLowMemory() { - mapView.onLowMemory() - } - - override fun onTrimMemory(level: Int) { - mapView.onLowMemory() - } - } + val componentCallbacks = mapView.componentCallbacks2() context.registerComponentCallbacks(componentCallbacks) val lifecycleObserver = MapLifecycleEventObserver(mapView) @@ -397,6 +383,24 @@ internal class MapAttachStateChangeListener(private val lifecycleObserver: MapLi } } +internal fun MapView.componentCallbacks2(): ComponentCallbacks2 = object : ComponentCallbacks2 { + override fun onConfigurationChanged(newConfig: Configuration) {} + + @Deprecated( + "Deprecated in Java", + ReplaceWith("onTrimMemory(level)"), + ) + override fun onLowMemory() { + this@componentCallbacks2.onLowMemory() + } + + override fun onTrimMemory(level: Int) { + if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + this@componentCallbacks2.onLowMemory() + } + } +} + internal val MapView.tagDataOrNull: MapTagData? get() = tag as? MapTagData diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/streetview/StreetView.kt b/maps-compose/src/main/java/com/google/maps/android/compose/streetview/StreetView.kt index ef483ee0..8d10e197 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/streetview/StreetView.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/streetview/StreetView.kt @@ -191,7 +191,7 @@ private fun StreetViewPanoramaView.lifecycleObserver( previousState.value = event } -private fun StreetViewPanoramaView.componentCallbacks2(): ComponentCallbacks2 = object : ComponentCallbacks2 { +internal fun StreetViewPanoramaView.componentCallbacks2(): ComponentCallbacks2 = object : ComponentCallbacks2 { override fun onConfigurationChanged(config: Configuration) {} @Deprecated("Deprecated in Java", ReplaceWith("onTrimMemory(level)")) @@ -200,6 +200,8 @@ private fun StreetViewPanoramaView.componentCallbacks2(): ComponentCallbacks2 = } override fun onTrimMemory(level: Int) { - this@componentCallbacks2.onLowMemory() + if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + this@componentCallbacks2.onLowMemory() + } } } diff --git a/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierCleanupTest.kt b/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierCleanupTest.kt index 6d0694a9..9d0849e5 100644 --- a/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierCleanupTest.kt +++ b/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierCleanupTest.kt @@ -33,11 +33,13 @@ import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.MapView import com.google.android.gms.maps.OnMapReadyCallback +import com.google.android.gms.maps.StreetViewPanoramaView import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.Marker import com.google.android.gms.maps.model.TileOverlay import com.google.common.truth.Truth.assertThat +import com.google.maps.android.compose.streetview.componentCallbacks2 import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic @@ -399,4 +401,40 @@ public class MapApplierCleanupTest { unmockkStatic(Log::class) } } + + @Suppress("DEPRECATION") + @Test + public fun `MapView componentCallbacks2 only calls onLowMemory for UI_HIDDEN and higher`() { + val mapView = mockk(relaxed = true) + val callbacks = mapView.componentCallbacks2() + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE) + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) + verify(exactly = 0) { mapView.onLowMemory() } + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) + verify(exactly = 1) { mapView.onLowMemory() } + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) + verify(exactly = 2) { mapView.onLowMemory() } + } + + @Suppress("DEPRECATION") + @Test + public fun `StreetViewPanoramaView componentCallbacks2 only calls onLowMemory for UI_HIDDEN and higher`() { + val streetView = mockk(relaxed = true) + val callbacks = streetView.componentCallbacks2() + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE) + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) + verify(exactly = 0) { streetView.onLowMemory() } + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) + verify(exactly = 1) { streetView.onLowMemory() } + + callbacks.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) + verify(exactly = 2) { streetView.onLowMemory() } + } }