### Custom Cluster Renderer with DefaultClusterRenderer Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Override `DefaultClusterRenderer` to customize the visual appearance of cluster markers. This example shows how to set custom icons for individual items and clusters based on their size. ```kotlin class ColoredClusterRenderer(context: Context, map: GoogleMap, clusterManager: ClusterManager) : DefaultClusterRenderer(context, map, clusterManager) { override fun onBeforeClusterItemRendered(item: MyLocation, markerOptions: MarkerOptions) { markerOptions .title(item.getTitle()) .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)) } override fun onBeforeClusterRendered( cluster: Cluster, markerOptions: MarkerOptions ) { val color = when { cluster.size > 50 -> BitmapDescriptorFactory.HUE_RED cluster.size > 10 -> BitmapDescriptorFactory.HUE_ORANGE else -> BitmapDescriptorFactory.HUE_GREEN } markerOptions.icon(BitmapDescriptorFactory.defaultMarker(color)) } override fun shouldRenderAsCluster(cluster: Cluster) = cluster.size > 3 } // Attach the custom renderer clusterManager.setRenderer(ColoredClusterRenderer(this, googleMap, clusterManager)) ``` -------------------------------- ### Heatmap Tile Provider with HeatmapTileProvider Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Use `HeatmapTileProvider` to render a large collection of points as a tile-based heat map overlay. Supports both unweighted and weighted data, and allows dynamic updates. ```kotlin // Unweighted heatmap val locations = listOf( LatLng(37.7749, -122.4194), LatLng(37.7849, -122.4094), LatLng(37.7649, -122.4294) // … many more points ) val provider = HeatmapTileProvider.Builder() .data(locations) .radius(40) // blur radius in pixels, 10–50 .opacity(0.8) .build() val tileOverlay = googleMap.addTileOverlay(TileOverlayOptions().tileProvider(provider)) // Weighted heatmap (e.g. earthquake magnitudes) val weightedLocations = listOf( WeightedLatLng(LatLng(37.7749, -122.4194), intensity = 5.0), WeightedLatLng(LatLng(37.7849, -122.4094), intensity = 2.5) ) val weightedProvider = HeatmapTileProvider.Builder() .weightedData(weightedLocations) .gradient(Gradient( intArrayOf(Color.GREEN, Color.YELLOW, Color.RED), floatArrayOf(0.2f, 0.6f, 1.0f) )) .build() googleMap.addTileOverlay(TileOverlayOptions().tileProvider(weightedProvider)) // Dynamically update data (e.g. real-time sensor feed) provider.updateLatLngs(newLocations) tileOverlay?.clearTileCache() ``` -------------------------------- ### Implement Marker Clustering with ClusterManager Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Implement ClusterItem for your data model and set up ClusterManager in your Activity or Fragment. Register listeners and handle item/cluster clicks. ```kotlin class MyLocation(private val lat: Double, private val lng: Double, private val name: String) : ClusterItem { override fun getPosition() = LatLng(lat, lng) override fun getTitle() = name override fun getSnippet() = null override fun getZIndex() = null } ``` ```kotlin class MapActivity : AppCompatActivity(), OnMapReadyCallback { private lateinit var clusterManager: ClusterManager override fun onMapReady(googleMap: GoogleMap) { clusterManager = ClusterManager(this, googleMap) // Register listeners googleMap.setOnCameraIdleListener(clusterManager) googleMap.setOnMarkerClickListener(clusterManager) // Handle individual item clicks clusterManager.setOnClusterItemClickListener { item -> Toast.makeText(this, "Clicked: ${item.getTitle()}", Toast.LENGTH_SHORT).show() true // consume event } // Handle cluster clicks clusterManager.setOnClusterClickListener { cluster -> Toast.makeText(this, "${cluster.size} items here", Toast.LENGTH_SHORT).show() false // allow default behavior (zoom in) } // Add items and trigger initial clustering val items = listOf( MyLocation(51.5074, -0.1278, "London"), MyLocation(48.8566, 2.3522, "Paris"), MyLocation(52.5200, 13.4050, "Berlin"), MyLocation(41.9028, 12.4964, "Rome") ) clusterManager.addItems(items) clusterManager.cluster() } } ``` -------------------------------- ### KML Import with KmlLayer Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Parses KML and KMZ files for rendering on the map. The constructor can be called on a background thread, but addLayerToMap() must be on the main UI thread. Handles raw resources or InputStreams with optional security limits for KMZ. ```kotlin lifecycleScope.launch(Dispatchers.IO) { try { val layer = KmlLayer(googleMap, R.raw.regions, applicationContext) withContext(Dispatchers.Main) { layer.addLayerToMap() // Iterate placemarks for (placemark in layer.placemarks) { Log.d("KML", "Placemark: ${placemark.getProperty("name")}") } } } catch (e: XmlPullParserException) { Log.e("KML", "Parse error", e) } catch (e: IOException) { Log.e("KML", "IO error", e) } } ``` ```kotlin val inputStream = assets.open("buildings.kmz") val layer = KmlLayer( googleMap, inputStream, applicationContext, maxKmzEntryCount = 100, maxKmzUncompressedTotalSize = 20 * 1024 * 1024L // 20 MB ) layer.addLayerToMap() ``` -------------------------------- ### Configure API Keys in secrets.properties Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Create a secrets.properties file in the root of your project to store API keys securely. This file should not be committed to version control. ```properties MAPS_API_KEY=YOUR_MAPS_API_KEY PLACES_API_KEY=YOUR_PLACES_API_KEY MAP_ID=YOUR_MAP_ID ``` -------------------------------- ### Polyline Encoding and Decoding - PolyUtil Source: https://context7.com/googlemaps/android-maps-utils/llms.txt `PolyUtil` provides Google's Encoded Polyline Algorithm for compact path serialization, geometric predicates (point-in-polygon, point-on-path), and Douglas-Peucker simplification. ```APIDOC ## Polyline Encoding and Decoding — `PolyUtil` `PolyUtil` provides Google's Encoded Polyline Algorithm for compact path serialization, plus geometric predicates (point-in-polygon, point-on-path) and Douglas-Peucker simplification. ```kotlin // Encode a list of LatLng points to a compact string val path = listOf( LatLng(38.5, -120.2), LatLng(40.7, -120.95), LatLng(43.252, -126.453) ) val encoded = PolyUtil.encode(path) // encoded = "_p~iF~ps|U_ulLnnqC_mqNvxq`@" // Decode back to LatLng list val decoded: List = PolyUtil.decode("_p~iF~ps|U_ulLnnqC_mqNvxq`@") // Check if a point is inside a polygon (geodesic segments) val polygon = listOf( LatLng(0.0, 0.0), LatLng(0.0, 10.0), LatLng(10.0, 10.0), LatLng(10.0, 0.0) ) val inside = PolyUtil.containsLocation(LatLng(5.0, 5.0), polygon, geodesic = true) // true val outside = PolyUtil.containsLocation(LatLng(15.0, 5.0), polygon, geodesic = true) // false // Check if a point is on (or near) a polyline within 10m tolerance val onPath = PolyUtil.isLocationOnPath( LatLng(40.7, -120.95), decoded, geodesic = true, tolerance = 10.0 ) // Simplify a polyline using Douglas-Peucker (reduce points for rendering) val simplified: List = PolyUtil.simplify(path, tolerance = 500.0) // 500m tolerance ``` ``` -------------------------------- ### Spherical Geometry Calculations with SphericalUtil Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Provides great-circle math functions for distances, headings, areas, offsets, and interpolation over the Earth's surface. Supports calculating distances, headings, offsets, interpolation, area of polygons, path lengths, and points along a polyline. ```kotlin val london = LatLng(51.5074, -0.1278) val paris = LatLng(48.8566, 2.3522) // Distance between two points (meters) val distanceMeters = SphericalUtil.computeDistanceBetween(london, paris) // ≈ 340,500 m ``` ```kotlin // Heading from London to Paris (degrees clockwise from North) val heading = SphericalUtil.computeHeading(london, paris) // ≈ 156.8° ``` ```kotlin // Point 100 km south-east of London val destination = SphericalUtil.computeOffset(london, distance = 100_000.0, heading = 135.0) // ≈ LatLng(50.74, 1.03) ``` ```kotlin // Interpolate 25% of the way from London to Paris (great-circle SLERP) val quarter = SphericalUtil.interpolate(london, paris, fraction = 0.25) ``` ```kotlin // Area of a closed polygon (m²) val region = listOf( LatLng(51.5, -0.1), LatLng(51.5, 0.0), LatLng(51.4, 0.0), LatLng(51.4, -0.1) ) val areaSqMeters = SphericalUtil.computeArea(region) ``` ```kotlin // Total length of a path val route = listOf(london, LatLng(50.0, 1.0), paris) val routeLength = SphericalUtil.computeLength(route) ``` ```kotlin // Point at 60% along a polyline val point = SphericalUtil.getPointOnPolyline(route, 0.60) ``` ```kotlin // First 40% of a polyline as a new polyline val prefix: List = SphericalUtil.getPolylinePrefix(route, 0.40) ``` -------------------------------- ### KML Import - KmlLayer Source: https://context7.com/googlemaps/android-maps-utils/llms.txt `KmlLayer` allows parsing and rendering KML/KMZ files on the map. The constructor can be called on a background thread, but `addLayerToMap()` must be on the main UI thread. ```APIDOC ## KML Import — `KmlLayer` `KmlLayer` parses KML and KMZ files and renders their placemarks, lines, polygons, and ground overlays on the map. The constructor is safe to call on a background thread due to I/O; `addLayerToMap()` must be called on the main UI thread. ```kotlin // From raw resource (res/raw/regions.kml) lifecycleScope.launch(Dispatchers.IO) { try { val layer = KmlLayer(googleMap, R.raw.regions, applicationContext) withContext(Dispatchers.Main) { layer.addLayerToMap() // Iterate placemarks for (placemark in layer.placemarks) { Log.d("KML", "Placemark: ${placemark.getProperty("name")}") } } } catch (e: XmlPullParserException) { Log.e("KML", "Parse error", e) } catch (e: IOException) { Log.e("KML", "IO error", e) } } // From an InputStream (e.g. downloaded file) with KMZ security limits val inputStream = assets.open("buildings.kmz") val layer = KmlLayer( googleMap, inputStream, applicationContext, maxKmzEntryCount = 100, maxKmzUncompressedTotalSize = 20 * 1024 * 1024L // 20 MB ) layer.addLayerToMap() ``` ``` -------------------------------- ### Encode and Decode Polylines with PolyUtil Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Utilizes Google's Encoded Polyline Algorithm for compact path serialization. Supports decoding to LatLng lists, checking if a point is inside a polygon or on a path with tolerance, and simplifying polylines using Douglas-Peucker. ```kotlin // Encode a list of LatLng points to a compact string val path = listOf( LatLng(38.5, -120.2), LatLng(40.7, -120.95), LatLng(43.252, -126.453) ) val encoded = PolyUtil.encode(path) // encoded = "_p~iF~ps|U_ulLnnqC_mqNvxq`@" ``` ```kotlin // Decode back to LatLng list val decoded: List = PolyUtil.decode("_p~iF~ps|U_ulLnnqC_mqNvxq`@") ``` ```kotlin // Check if a point is inside a polygon (geodesic segments) val polygon = listOf( LatLng(0.0, 0.0), LatLng(0.0, 10.0), LatLng(10.0, 10.0), LatLng(10.0, 0.0) ) val inside = PolyUtil.containsLocation(LatLng(5.0, 5.0), polygon, geodesic = true) // true val outside = PolyUtil.containsLocation(LatLng(15.0, 5.0), polygon, geodesic = true) // false ``` ```kotlin // Check if a point is on (or near) a polyline within 10m tolerance val onPath = PolyUtil.isLocationOnPath( LatLng(40.7, -120.95), decoded, geodesic = true, tolerance = 10.0 ) ``` ```kotlin // Simplify a polyline using Douglas-Peucker (reduce points for rendering) val simplified: List = PolyUtil.simplify(path, tolerance = 500.0) // 500m tolerance ``` -------------------------------- ### Check Street View Support Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Use StreetViewUtils to check if a location is supported by Street View before attempting to display a panorama. This helps prevent errors. The default source is Source.DEFAULT, but Source.OUTDOOR can be specified for outdoor panoramas. ```kotlin StreetViewUtils.fetchStreetViewData(LatLng(8.1425918, 11.5386121), BuildConfig.MAPS_API_KEY,Source.DEFAULT) ``` -------------------------------- ### Generate Marker Icons with IconGenerator Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Renders text labels or custom views into Bitmap objects for use as Marker icons. Supports built-in styles, custom color tints, and fully custom views. The anchor point can also be set. ```kotlin val iconGenerator = IconGenerator(context) // Built-in styles: STYLE_DEFAULT, STYLE_WHITE, STYLE_RED, STYLE_BLUE, // STYLE_GREEN, STYLE_PURPLE, STYLE_ORANGE iconGenerator.setStyle(IconGenerator.STYLE_BLUE) val blueIcon: Bitmap = iconGenerator.makeIcon("Cafe") // Apply to a marker googleMap.addMarker( MarkerOptions() .position(LatLng(48.8566, 2.3522)) .icon(BitmapDescriptorFactory.fromBitmap(blueIcon)) .anchor(iconGenerator.anchorU, iconGenerator.anchorV) ) ``` ```kotlin // Custom color tint iconGenerator.setColor(Color.parseColor("#FF5722")) val customIcon: Bitmap = iconGenerator.makeIcon("Shop") ``` ```kotlin // Custom view (e.g. inflated layout with image + text) val customView = layoutInflater.inflate(R.layout.custom_marker, null) iconGenerator.setContentView(customView) val customBitmap: Bitmap = iconGenerator.makeIcon() ``` -------------------------------- ### Add Kotlin Extensions Dependency Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Optionally, add the Kotlin Extensions (KTX) for full Kotlin language support. Check the repository for the latest version. ```groovy implementation 'com.google.maps.android:maps-utils-ktx:' ``` -------------------------------- ### Spherical Geometry - SphericalUtil Source: https://context7.com/googlemaps/android-maps-utils/llms.txt `SphericalUtil` provides great-circle math functions including distances, headings, areas, offsets, and interpolation over the Earth's surface. ```APIDOC ## Spherical Geometry — `SphericalUtil` `SphericalUtil` provides great-circle math: distances, headings, areas, offsets, and interpolation over the surface of the Earth. ```kotlin val london = LatLng(51.5074, -0.1278) val paris = LatLng(48.8566, 2.3522) // Distance between two points (meters) val distanceMeters = SphericalUtil.computeDistanceBetween(london, paris) // ≈ 340,500 m // Heading from London to Paris (degrees clockwise from North) val heading = SphericalUtil.computeHeading(london, paris) // ≈ 156.8° // Point 100 km south-east of London val destination = SphericalUtil.computeOffset(london, distance = 100_000.0, heading = 135.0) // ≈ LatLng(50.74, 1.03) // Interpolate 25% of the way from London to Paris (great-circle SLERP) val quarter = SphericalUtil.interpolate(london, paris, fraction = 0.25) // Area of a closed polygon (m²) val region = listOf( LatLng(51.5, -0.1), LatLng(51.5, 0.0), LatLng(51.4, 0.0), LatLng(51.4, -0.1) ) val areaSqMeters = SphericalUtil.computeArea(region) // Total length of a path val route = listOf(london, LatLng(50.0, 1.0), paris) val routeLength = SphericalUtil.computeLength(route) // Point at 60% along a polyline val point = SphericalUtil.getPointOnPolyline(route, 0.60) // First 40% of a polyline as a new polyline val prefix: List = SphericalUtil.getPolylinePrefix(route, 0.40) ``` ``` -------------------------------- ### Animate Marker Position with AnimationUtil Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Smoothly moves a map marker to a new position using an AccelerateDecelerateInterpolator on the main thread. Supports default or custom durations. ```kotlin val marker = googleMap.addMarker( MarkerOptions().position(LatLng(51.5074, -0.1278)).title("Moving marker") )!! // Animate to a new position over the default 2 000 ms AnimationUtil.animateMarkerTo(marker, LatLng(48.8566, 2.3522)) ``` ```kotlin // Animate with a custom duration AnimationUtil.animateMarkerTo( marker, finalPosition = LatLng(52.5200, 13.4050), durationInMs = 3_000L ) ``` ```kotlin // Simulate a moving vehicle updating every 5 seconds lifecycleScope.launch { for (update in vehiclePositionFlow) { AnimationUtil.animateMarkerTo(marker, update.latLng, durationInMs = 4_500L) delay(5_000L) } } ``` -------------------------------- ### Fetch Street View Metadata with StreetViewUtils Source: https://context7.com/googlemaps/android-maps-utils/llms.txt A suspending function to check for Street View panorama existence at a given location before launching a Street View fragment. Requires an API key and specifies the data source. ```kotlin // In a coroutine (e.g. viewModelScope or lifecycleScope) lifecycleScope.launch { val location = LatLng(48.8584, 2.2945) // Eiffel Tower val status = StreetViewUtils.fetchStreetViewData( latLng = location, apiKey = BuildConfig.MAPS_API_KEY, source = Source.DEFAULT // or Source.OUTDOOR for outdoor-only ) when (status) { Status.OK -> { // Safe to load the Street View panorama val panoramaFragment = SupportStreetViewPanoramaFragment.newInstance() supportFragmentManager.beginTransaction() .replace(R.id.streetview_container, panoramaFragment) .commit() panoramaFragment.getStreetViewPanoramaAsync { panorama -> panorama.setPosition(location) } } Status.NOT_FOUND, Status.ZERO_RESULTS -> showMessage("No Street View available here") Status.REQUEST_DENIED -> showMessage("Invalid API key") else -> showMessage("Error: $status") } } ``` -------------------------------- ### GeoJSON Import with GeoJsonLayer Source: https://context7.com/googlemaps/android-maps-utils/llms.txt `GeoJsonLayer` parses and renders GeoJSON data as styled features on the map. Supports loading from raw resources or JSON objects, and allows styling and click listeners. ```kotlin // Load from raw resource (res/raw/map_features.geojson) try { val layer = GeoJsonLayer(googleMap, R.raw.map_features, applicationContext) layer.addLayerToMap() // Style all polygon features for (feature in layer.features) { if (feature.hasProperty("type") && feature.getProperty("type") == "park") { feature.polygonStyle = GeoJsonPolygonStyle().apply { fillColor = Color.argb(100, 0, 180, 0) strokeColor = Color.GREEN strokeWidth = 2f } } } // Click listener on individual features layer.setOnFeatureClickListener { feature -> val name = feature.getProperty("name") ?: "Unknown" Toast.makeText(applicationContext, "Feature: $name", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { Log.e("GeoJSON", "Error loading layer", e) } catch (e: JSONException) { Log.e("GeoJSON", "Error parsing JSON", e) } // Load from a JSONObject (e.g. fetched from network) val jsonObject = JSONObject(rawGeoJsonString) val dynamicLayer = GeoJsonLayer(googleMap, jsonObject) dynamicLayer.addLayerToMap() ``` -------------------------------- ### Incrementally Update Clusters with ClusterManager.diff() Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Use diff() to atomically add, remove, and update items in a cluster, avoiding redundant cluster() calls. Apply all changes at once. ```kotlin // Add new arrivals, remove departed, update moved items val newItems = listOf(MyLocation(55.7558, 37.6173, "Moscow")) val removedItems = listOf(existingLondon) val updatedItems = listOf(MyLocation(48.8566, 2.3522, "Paris (updated)")) clusterManager.diff( add = newItems, remove = removedItems, modify = updatedItems ) clusterManager.cluster() // apply all changes at once ``` -------------------------------- ### Add Maps SDK for Android Utility Library Dependency Source: https://context7.com/googlemaps/android-maps-utils/llms.txt Add the dependency to your build.gradle file to include the library in your Android project. ```groovy dependencies { implementation 'com.google.maps.android:android-maps-utils:3.20.1' // Optional Kotlin extensions // implementation 'com.google.maps.android:maps-utils-ktx:' } ``` -------------------------------- ### Marker Icon Generator - IconGenerator Source: https://context7.com/googlemaps/android-maps-utils/llms.txt `IconGenerator` creates `Bitmap` objects from text labels or custom views for use as `MarkerOptions` icons, offering built-in styles and custom view support. ```APIDOC ## Marker Icon Generator — `IconGenerator` `IconGenerator` renders text labels (or arbitrary views) into `Bitmap` objects suitable for use as custom `MarkerOptions` icons, with seven built-in color styles and full custom-view support. ```kotlin val iconGenerator = IconGenerator(context) // Built-in styles: STYLE_DEFAULT, STYLE_WHITE, STYLE_RED, STYLE_BLUE, // STYLE_GREEN, STYLE_PURPLE, STYLE_ORANGE iconGenerator.setStyle(IconGenerator.STYLE_BLUE) val blueIcon: Bitmap = iconGenerator.makeIcon("Cafe") // Apply to a marker googleMap.addMarker( MarkerOptions() .position(LatLng(48.8566, 2.3522)) .icon(BitmapDescriptorFactory.fromBitmap(blueIcon)) .anchor(iconGenerator.anchorU, iconGenerator.anchorV) ) // Custom color tint iconGenerator.setColor(Color.parseColor("#FF5722")) val customIcon: Bitmap = iconGenerator.makeIcon("Shop") // Custom view (e.g. inflated layout with image + text) val customView = layoutInflater.inflate(R.layout.custom_marker, null) iconGenerator.setContentView(customView) val customBitmap: Bitmap = iconGenerator.makeIcon() ``` ``` -------------------------------- ### Add Android Maps Utils Dependency Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Include this dependency in your app's build.gradle file to use the Maps SDK for Android Utility Library. The Maps SDK for Android is automatically included. ```groovy implementation 'com.google.maps.android:android-maps-utils:3.20.1' ``` -------------------------------- ### Set Map ID in strings.xml Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Alternatively, define your Map ID within the strings.xml file for use in your Android application. ```xml YOUR_MAP_ID ``` -------------------------------- ### Set Map ID in XML Layout Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Hardcode the Map ID directly in your XML layout files by setting the map:mapId attribute on a map fragment. ```xml ``` -------------------------------- ### Set Map ID in secrets.properties Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md Add your Map ID to the secrets.properties file for features requiring it, such as Advanced Markers. ```properties MAP_ID=YOUR_MAP_ID ``` -------------------------------- ### Remove Attribution ID Initializer Source: https://github.com/googlemaps/android-maps-utils/blob/main/README.md To disable the internal usage attribution ID, remove the AttributionIdInitializer from your AndroidManifest.xml using the tools:node="remove" attribute. ```xml ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.