Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,49 @@ class GoogleMapViewTests {
}
}

@Test
fun testAdvancedMarkerInfoWindowContentDoesNotCrash() {
// Regression test for https://github.com/googlemaps/android-maps-compose/issues/822:
// AdvancedMarker didn't expose infoContent/infoWindow customization, even though the
// underlying implementation already supported it. Custom info window content is
// rendered to a bitmap by ComposeInfoWindowAdapter (not present in the Compose
// semantics tree), so this asserts the composable wires up and shows without crashing
// rather than asserting on-screen content.
lateinit var markerState: MarkerState

initMap {
markerState = rememberUpdatedMarkerState(position = startingPosition)
AdvancedMarkerInfoWindowContent(state = markerState) {
Text(text = "custom advanced marker info window")
}
}

composeTestRule.runOnUiThread {
markerState.showInfoWindow()
}
composeTestRule.waitForIdle()
}

@Test
fun testAdvancedMarkerInfoWindowDoesNotCrash() {
// Regression test for https://github.com/googlemaps/android-maps-compose/issues/822:
// see testAdvancedMarkerInfoWindowContentDoesNotCrash for why this doesn't assert
// on-screen content.
lateinit var markerState: MarkerState

initMap {
markerState = rememberUpdatedMarkerState(position = startingPosition)
AdvancedMarkerInfoWindow(state = markerState) {
Text(text = "custom advanced marker whole info window")
}
}

composeTestRule.runOnUiThread {
markerState.showInfoWindow()
}
composeTestRule.waitForIdle()
}

@Test(expected = IllegalStateException::class)
fun testMarkerStateInsideMarkerInfoWindowComposableCannotBeReused() {
initMap {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color as ComposeColor
import androidx.compose.ui.unit.dp
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.MapsInitializer
import com.google.android.gms.maps.OnMapsSdkInitializedCallback
Expand All @@ -40,6 +45,7 @@ import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.PinConfig
import com.google.maps.android.compose.AdvancedMarker
import com.google.maps.android.compose.AdvancedMarkerInfoWindowContent
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.MapProperties
import com.google.maps.android.compose.MapType
Expand Down Expand Up @@ -138,13 +144,24 @@ class AdvancedMarkersActivity : ComponentActivity(), OnMapsSdkInitializedCallbac
.setBorderColor(Color.WHITE)
.build()

AdvancedMarker(
// AdvancedMarkerInfoWindowContent lets you customize the info window's
// content while keeping the default info window frame. Tap this marker
// to see it.
AdvancedMarkerInfoWindowContent(
state = marker1State,
onClick = markerClick,
collisionBehavior = 1,
pinConfig = pinConfig,
title="Marker 1"
)
title = "Marker 1"
) {
Box(
modifier = Modifier
.background(ComposeColor.Yellow)
.padding(8.dp)
) {
Text("Custom advanced marker info window!")
}
}

val glyphOne = PinConfig.Glyph("A", Color.BLACK)
val pinConfig2 = PinConfig.builder()
Expand Down
164 changes: 164 additions & 0 deletions maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,170 @@ public fun AdvancedMarker(
)
}

/**
* A composable for an advanced marker on the map wherein its entire info window can be
* customized. If this customization is not required, use
* [com.google.maps.android.compose.AdvancedMarker].
*
* @param state the [MarkerState] to be used to control or observe the marker
* state such as its position and info window
* @param contentDescription the content description for accessibility purposes
* @param alpha the alpha (opacity) of the marker
* @param anchor the anchor for the marker image
* @param draggable sets the draggability for the marker
* @param flat sets if the marker should be flat against the map
* @param infoWindowAnchor the anchor point of the info window on the marker image
* @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point
* @param snippet the snippet for the marker
* @param tag optional tag to associate with the marker
* @param title the title for the marker
* @param visible the visibility of the marker
* @param zIndex the z-index of the marker
* @param onClick a lambda invoked when the marker is clicked
* @param onInfoWindowClick a lambda invoked when the marker's info window is clicked
* @param onInfoWindowClose a lambda invoked when the marker's info window is closed
* @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked
* @param icon sets the icon for the marker
* @param pinConfig the PinConfig object that will be used for the advanced marker
* @param iconView the custom view to be used on the advanced marker
* @param collisionBehavior the expected collision behavior
* @param content optional composable lambda expression for customizing the
* info window's content
*/
@Composable
@GoogleMapComposable
public fun AdvancedMarkerInfoWindow(
state: MarkerState = rememberUpdatedMarkerState(),
contentDescription: String? = "",
alpha: Float = 1.0f,
anchor: Offset = Offset(0.5f, 1.0f),
draggable: Boolean = false,
flat: Boolean = false,
infoWindowAnchor: Offset = Offset(0.5f, 0.0f),
rotation: Float = 0.0f,
snippet: String? = null,
tag: Any? = null,
title: String? = null,
visible: Boolean = true,
zIndex: Float = 0.0f,
onClick: (Marker) -> Boolean = { false },
onInfoWindowClick: (Marker) -> Unit = {},
onInfoWindowClose: (Marker) -> Unit = {},
onInfoWindowLongClick: (Marker) -> Unit = {},
icon: BitmapDescriptor? = null,
pinConfig: PinConfig? = null,
iconView: View? = null,
collisionBehavior: Int = AdvancedMarkerOptions.CollisionBehavior.REQUIRED,
content: (@UiComposable @Composable (Marker) -> Unit)? = null,
) {
AdvancedMarkerImpl(
state = state,
contentDescription = contentDescription,
alpha = alpha,
anchor = anchor,
draggable = draggable,
flat = flat,
infoWindowAnchor = infoWindowAnchor,
rotation = rotation,
snippet = snippet,
tag = tag,
title = title,
visible = visible,
zIndex = zIndex,
onClick = onClick,
onInfoWindowClick = onInfoWindowClick,
onInfoWindowClose = onInfoWindowClose,
onInfoWindowLongClick = onInfoWindowLongClick,
icon = icon,
pinConfig = pinConfig,
iconView = iconView,
collisionBehavior = collisionBehavior,
infoWindow = content,
)
}

/**
* A composable for an advanced marker on the map wherein its info window contents can be
* customized. If this customization is not required, use
* [com.google.maps.android.compose.AdvancedMarker].
*
* @param state the [MarkerState] to be used to control or observe the marker
* state such as its position and info window
* @param contentDescription the content description for accessibility purposes
* @param alpha the alpha (opacity) of the marker
* @param anchor the anchor for the marker image
* @param draggable sets the draggability for the marker
* @param flat sets if the marker should be flat against the map
* @param infoWindowAnchor the anchor point of the info window on the marker image
* @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point
* @param snippet the snippet for the marker
* @param tag optional tag to associate with the marker
* @param title the title for the marker
* @param visible the visibility of the marker
* @param zIndex the z-index of the marker
* @param onClick a lambda invoked when the marker is clicked
* @param onInfoWindowClick a lambda invoked when the marker's info window is clicked
* @param onInfoWindowClose a lambda invoked when the marker's info window is closed
* @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked
* @param icon sets the icon for the marker
* @param pinConfig the PinConfig object that will be used for the advanced marker
* @param iconView the custom view to be used on the advanced marker
* @param collisionBehavior the expected collision behavior
* @param content optional composable lambda expression for customizing the
* info window's content
*/
@Composable
@GoogleMapComposable
public fun AdvancedMarkerInfoWindowContent(
state: MarkerState = rememberUpdatedMarkerState(),
contentDescription: String? = "",
alpha: Float = 1.0f,
anchor: Offset = Offset(0.5f, 1.0f),
draggable: Boolean = false,
flat: Boolean = false,
infoWindowAnchor: Offset = Offset(0.5f, 0.0f),
rotation: Float = 0.0f,
snippet: String? = null,
tag: Any? = null,
title: String? = null,
visible: Boolean = true,
zIndex: Float = 0.0f,
onClick: (Marker) -> Boolean = { false },
onInfoWindowClick: (Marker) -> Unit = {},
onInfoWindowClose: (Marker) -> Unit = {},
onInfoWindowLongClick: (Marker) -> Unit = {},
icon: BitmapDescriptor? = null,
pinConfig: PinConfig? = null,
iconView: View? = null,
collisionBehavior: Int = AdvancedMarkerOptions.CollisionBehavior.REQUIRED,
content: (@UiComposable @Composable (Marker) -> Unit)? = null,
) {
AdvancedMarkerImpl(
state = state,
contentDescription = contentDescription,
alpha = alpha,
anchor = anchor,
draggable = draggable,
flat = flat,
infoWindowAnchor = infoWindowAnchor,
rotation = rotation,
snippet = snippet,
tag = tag,
title = title,
visible = visible,
zIndex = zIndex,
onClick = onClick,
onInfoWindowClick = onInfoWindowClick,
onInfoWindowClose = onInfoWindowClose,
onInfoWindowLongClick = onInfoWindowLongClick,
icon = icon,
pinConfig = pinConfig,
iconView = iconView,
collisionBehavior = collisionBehavior,
infoContent = content,
)
}

/**
* Internal implementation for an advanced marker on a Google map.
*
Expand Down