Skip to content

Commit e3685c6

Browse files
authored
chore: demo tile overlay state fix (#769)
* chore(demo): Export all sample activities Updated the `AndroidManifest.xml` in the `maps-app` sample to set `android:exported="true"` for all sample activities. This change allows each activity to be launched directly, simplifying demonstration and testing. * feat(maps-app): Group demo activities on main screen To make the main screen less cluttered and easier to navigate, the demo activities have been grouped into a list. This provides a cleaner and more organized user experience. This change also pulls in Material 3. * feat(maps-app): Use Material 3 Scaffold This commit updates the main screen to use a Material 3 Scaffold, providing a more modern and consistent layout. The TopAppBar has also been updated to be center-aligned. * refactor(demo): Extract strings and refactor list composables Refactored the demo list screen to support internationalization by extracting all hardcoded strings into `strings.xml`. The `Activity` and `ActivityGroup` data classes were updated to use `@StringRes` integer IDs instead of `String` literals. Additionally, the `DemoList` composable has been broken down into smaller, more focused composables (`GroupHeaderItem` and `DemoActivityItem`) to improve readability and maintainability. * chore(demo): Add copyright header to Demo.kt and clean up unused import * docs: Improve comment for expanded group state in DemoList * chore: Add TileOverlay demo activity This commit introduces a new example activity, `TileOverlayActivity`, to demonstrate the usage and dynamic updating of the `TileOverlay` composable. The demo showcases: - Providing custom tiles using a `TileProvider`. - Refreshing tile content by calling `clearTileCache()` on the `TileOverlayState`. The example updates tiles every second to display an incrementing number. - Replacing the `TileProvider` instance to trigger a full refresh of the overlay. The new activity is registered in the manifest and is accessible from the main screen of the demo application. * feat: Relocate TileOverlayActivity to Demo.kt The TileOverlayActivity was previously launched from a standalone button in MainActivity. This commit moves it into the "Map Features" group within Demo.kt, ensuring a more consistent and organized user experience. This change also removes the now-redundant button from MainActivity. * feat(maps-app): make TileOverlayActivity more idiomatic * docs: Added detailed comments to the `TileOverlayActivity` sample to better demonstrate how to update a `TileOverlay`. The `LaunchedEffect` in `TileOverlayDemo` now includes comments explaining two distinct update strategies: 1. **Cache Invalidation**: Calling `state.clearTileCache()` to force a redraw of tiles using the existing `TileProvider`. 2. **Provider Replacement**: Creating a new `TileProvider` instance, which triggers a full replacement of the overlay's data source.
1 parent 7321201 commit e3685c6

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

maps-app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
<activity
101101
android:name=".markerexamples.draggablemarkerscollectionwithpolygon.DraggableMarkersCollectionWithPolygonActivity"
102102
android:exported="true"/>
103+
<activity
104+
android:name=".TileOverlayActivity"
105+
android:exported="true"/>
103106

104107
<!-- Used by createComponentActivity() for unit testing -->
105108
<activity android:name="androidx.activity.ComponentActivity" />

maps-app/src/main/java/com/google/maps/android/compose/Demo.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ sealed class ActivityGroup(
106106
R.string.accessibility_activity_description,
107107
AccessibilityActivity::class
108108
),
109+
Activity(
110+
R.string.tile_overlay_activity,
111+
R.string.tile_overlay_activity_description,
112+
TileOverlayActivity::class
113+
),
109114
)
110115
)
111116

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package com.google.maps.android.compose
2+
3+
import android.graphics.Bitmap
4+
import android.graphics.Canvas
5+
import android.graphics.Paint
6+
import android.os.Build
7+
import android.os.Bundle
8+
import androidx.activity.ComponentActivity
9+
import androidx.activity.compose.setContent
10+
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.runtime.LaunchedEffect
13+
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.mutableIntStateOf
15+
import androidx.compose.runtime.remember
16+
import androidx.compose.runtime.setValue
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.graphics.Color
19+
import androidx.compose.ui.graphics.toArgb
20+
import androidx.compose.ui.platform.LocalDensity
21+
import androidx.compose.ui.unit.dp
22+
import androidx.core.graphics.createBitmap
23+
import com.google.android.gms.maps.model.Tile
24+
import com.google.android.gms.maps.model.TileProvider
25+
import java.io.ByteArrayOutputStream
26+
import kotlinx.coroutines.delay
27+
28+
/**
29+
* This activity demonstrates how to use Tile Overlays with Jetpack Compose.
30+
*/
31+
class TileOverlayActivity : ComponentActivity() {
32+
override fun onCreate(savedInstanceState: Bundle?) {
33+
super.onCreate(savedInstanceState)
34+
setContent {
35+
Content()
36+
}
37+
}
38+
}
39+
40+
@Composable
41+
private fun Content() {
42+
GoogleMap(
43+
modifier = Modifier.fillMaxSize(),
44+
) {
45+
UpdatedTileOverlay()
46+
}
47+
}
48+
49+
/**
50+
* This composable demonstrates how to use a [TileOverlay] with a [TileProvider] that
51+
* updates its content periodically.
52+
*/
53+
@Composable
54+
private fun UpdatedTileOverlay() {
55+
var tileProviderIndex by remember { mutableIntStateOf(0) }
56+
var renderedIndex by remember { mutableIntStateOf(0) }
57+
val state = rememberTileOverlayState()
58+
59+
val size = with(LocalDensity.current) { 256.dp.toPx() }.toInt()
60+
val tileProvider = remember(tileProviderIndex) {
61+
TileProvider { _, _, _ ->
62+
Tile(size, size, renderTiles(renderedIndex, size))
63+
}
64+
}
65+
66+
TileOverlay(tileProvider = tileProvider, state = state, fadeIn = false)
67+
68+
LaunchedEffect(Unit) {
69+
// This LaunchedEffect demonstrates two ways to update a tile overlay.
70+
71+
// 1. Invalidate the cache to redraw tiles with new data.
72+
// Here, we're calling `state.clearTileCache()` every second for 5 seconds.
73+
// This tells the map to request new tiles from the *existing* TileProvider,
74+
// which will then re-render them using the latest `renderedIndex`.
75+
repeat(5) {
76+
delay(1000)
77+
renderedIndex += 1
78+
state.clearTileCache()
79+
}
80+
81+
// 2. Update the TileProvider instance itself.
82+
// After 5 seconds, we update `tileProviderIndex`. Because this is a key
83+
// to the `remember` block for our TileProvider, Compose will discard the
84+
// old provider and create a new one.
85+
tileProviderIndex += 1
86+
87+
// Now, we continue invalidating the cache to demonstrate that the *new*
88+
// TileProvider is the one responding to the `clearTileCache` calls.
89+
while (true) {
90+
delay(1000)
91+
renderedIndex += 1
92+
state.clearTileCache()
93+
}
94+
}
95+
}
96+
97+
/**
98+
* Helper function to dynamically generate a tile image.
99+
* The [TileProvider] interface requires that a [ByteArray] is returned for each tile.
100+
* This function creates a [Bitmap], draws the current [index] on it, and then compresses
101+
* it into a [ByteArray] to be returned by the provider.
102+
*/
103+
private fun renderTiles(index: Int, size: Int): ByteArray {
104+
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
105+
textAlign = Paint.Align.CENTER
106+
color = Color.Black.toArgb()
107+
textSize = 100f
108+
}
109+
val bitmap = createBitmap(size, size).also {
110+
Canvas(it).drawText(index.toString(), size / 2f, size / 2f, paint)
111+
}
112+
113+
val format = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
114+
Bitmap.CompressFormat.WEBP_LOSSLESS
115+
} else {
116+
Bitmap.CompressFormat.PNG
117+
}
118+
119+
return ByteArrayOutputStream().use { stream ->
120+
bitmap.compress(format, 0, stream)
121+
stream.toByteArray()
122+
}
123+
}

maps-app/src/main/res/values/strings.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@
6969
<string name="recomposition_activity">Recomposition</string>
7070
<string name="recomposition_activity_description">Understanding how recomposition works with maps.</string>
7171

72+
<string name="tile_overlay_activity">Tile Overlay</string>
73+
<string name="tile_overlay_activity_description">Adding a tile overlay to the map.</string>
74+
7275
<!-- Demo group titles -->
7376
<string name="map_types_title">Map Types</string>
7477
<string name="map_features_title">Map Features</string>
7578
<string name="markers_title">Markers</string>
7679
<string name="ui_integration_title">UI Integration</string>
7780
<string name="performance_title">Performance</string>
78-
</resources>
81+
</resources>

0 commit comments

Comments
 (0)