From 3c847de97634cc55dd5a790b20a6e6abd9ea640d Mon Sep 17 00:00:00 2001
From: Dale Hawkins <107309+dkhawk@users.noreply.github.com>
Date: Tue, 18 Aug 2026 15:45:43 -0600
Subject: [PATCH] feat(markers,overlays): add custom badge iconView and
LatLngBounds camera framing
- Add custom framed circular badge iconView with Android logo to AdvancedMarkersDemoActivity (Kotlin & Java)
- Frame Southeast Asia markers on launch with LatLngBounds and 120px padding
- Initialize GroundOverlayDemoActivity with LatLngBounds framing and 0.2f default transparency
- Apply LatLngBounds with padding in DataDrivenDatasetStylingActivity to frame dataset layers
---
.../src/main/res/drawable/bg_marker_badge.xml | 26 ++++
.../mapdemo/AdvancedMarkersDemoActivity.java | 34 ++++-
.../DataDrivenDatasetStylingActivity.java | 43 +++---
.../mapdemo/GroundOverlayDemoActivity.java | 18 ++-
.../AdvancedMarkersDemoActivity.kt | 144 ++++++++++--------
.../DataDrivenDatasetStylingActivity.kt | 47 ++++--
.../kotlindemos/GroundOverlayDemoActivity.kt | 16 +-
7 files changed, 209 insertions(+), 119 deletions(-)
create mode 100644 ApiDemos/project/common-ui/src/main/res/drawable/bg_marker_badge.xml
diff --git a/ApiDemos/project/common-ui/src/main/res/drawable/bg_marker_badge.xml b/ApiDemos/project/common-ui/src/main/res/drawable/bg_marker_badge.xml
new file mode 100644
index 000000000..3b413cf19
--- /dev/null
+++ b/ApiDemos/project/common-ui/src/main/res/drawable/bg_marker_badge.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/AdvancedMarkersDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/AdvancedMarkersDemoActivity.java
index e91f17457..c66320770 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/AdvancedMarkersDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/AdvancedMarkersDemoActivity.java
@@ -1,4 +1,4 @@
-// Copyright 2023 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,10 +17,13 @@
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
+import com.example.common_ui.R;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
@@ -33,6 +36,7 @@
import com.google.android.gms.maps.model.AdvancedMarkerOptions;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MapCapabilities;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.PinConfig;
@@ -114,17 +118,33 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void onMapReady(GoogleMap map) {
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(SINGAPORE, ZOOM_LEVEL));
+ LatLngBounds bounds = new LatLngBounds.Builder()
+ .include(SINGAPORE)
+ .include(KUALA_LUMPUR)
+ .include(JAKARTA)
+ .include(BANGKOK)
+ .include(MANILA)
+ .include(HO_CHI_MINH_CITY)
+ .build();
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 120));
MapCapabilities capabilities = map.getMapCapabilities();
Log.d(TAG, "Are advanced markers enabled? " + capabilities.isAdvancedMarkersAvailable());
- // This sample sets a view as the iconView for the Advanced Marker
- TextView textView = new TextView(this);
- textView.setText("Hello!");
- Marker advancedMarkerView = map.addMarker(new AdvancedMarkerOptions()
+ // 1. Custom View as iconView (Framed circular badge with Android logo)
+ ImageView iconImageView = new ImageView(this);
+ iconImageView.setImageResource(R.drawable.ic_android);
+ iconImageView.setColorFilter(Color.parseColor("#3DDC84")); // Android Green
+ iconImageView.setBackgroundResource(R.drawable.bg_marker_badge);
+ int padding = (int) (8 * getResources().getDisplayMetrics().density);
+ iconImageView.setPadding(padding, padding, padding, padding);
+ int size = (int) (44 * getResources().getDisplayMetrics().density);
+ iconImageView.setLayoutParams(new ViewGroup.LayoutParams(size, size));
+
+ map.addMarker(new AdvancedMarkerOptions()
.position(SINGAPORE)
- .iconView(textView)
+ .iconView(iconImageView)
+ .title("Singapore (Custom Framed Badge)")
.zIndex(1f));
// This uses PinConfig.Builder to create an instance of PinConfig.
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
index 9173181a4..e829d35be 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
@@ -1,4 +1,4 @@
-// Copyright 2025 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
import com.google.android.gms.maps.model.FeatureStyle;
import com.google.android.gms.maps.model.FeatureType;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MapCapabilities;
import java.util.List;
@@ -58,8 +59,7 @@ public class DataDrivenDatasetStylingActivity extends SamplesBaseActivity implem
private record DataSet(
String label,
String datasetId,
- LatLng location,
- float zoomLevel,
+ LatLngBounds bounds,
DataDrivenDatasetStylingActivity.DataSet.StylingCallback callback) {
public interface StylingCallback {
void styleDatasetLayer();
@@ -71,25 +71,19 @@ public interface StylingCallback {
* Each DataSet contains:
* - A human-readable name (e.g., "Boulder", "New York").
* - A unique Dataset ID, which should correspond to a dataset id in the Datasets console tab.
- * - The central latitude and longitude coordinates (LatLng) of the location.
+ * - The LatLngBounds of the dataset area.
* - A styling function (method reference) that defines how to style the data from that dataset on a map.
- *
- * This array is used to configure which datasets are available for display and how they should be presented.
- * Each element of the array should be a new DataSet object.
- * Modify the constructor arguments of each DataSet to define your specific data and styles.
- * The styling function will receive a `Layer` to which it can add elements.
- *
- * Example:
- * - `new DataSet("Boulder", "Boulder-DataSet-Id", new LatLng(40.0150, -105.2705), this::styleBoulderDatasetLayer)`
- * This creates a DataSet for Boulder, identified by "Boulder-DataSet-Id", centered on the given coordinates,
- * and styled using the `styleBoulderDatasetLayer` method.
- *
- * Note: We have use the secrets plugin to allow us to configure the Dataset IDs in our secrets.properties file.
*/
private final DataSet[] dataSets = new DataSet[] {
- new DataSet("Boulder", BuildConfig.BOULDER_DATASET_ID, new LatLng(40.0150, -105.2705), 11f, this::styleBoulderDatasetLayer),
- new DataSet("New York", BuildConfig.NEW_YORK_DATASET_ID, new LatLng(40.786244, -73.962684), 14f, this::styleNYCDatasetLayer),
- new DataSet("Kyoto", BuildConfig.KYOTO_DATASET_ID, new LatLng(35.005081, 135.764385), 13.5f, this::styleKyotoDatasetsLayer),
+ new DataSet("Boulder", BuildConfig.BOULDER_DATASET_ID,
+ new LatLngBounds(new LatLng(39.920, -105.340), new LatLng(40.090, -105.210)),
+ this::styleBoulderDatasetLayer),
+ new DataSet("New York", BuildConfig.NEW_YORK_DATASET_ID,
+ new LatLngBounds(new LatLng(40.7640, -73.9820), new LatLng(40.8000, -73.9490)),
+ this::styleNYCDatasetLayer),
+ new DataSet("Kyoto", BuildConfig.KYOTO_DATASET_ID,
+ new LatLngBounds(new LatLng(34.9700, 135.7200), new LatLng(35.0400, 135.8000)),
+ this::styleKyotoDatasetsLayer),
};
private DataSet findDataSetByLabel(String label) {
@@ -176,7 +170,7 @@ private void switchDataSet(String label) {
.build()
);
dataSet.callback.styleDatasetLayer();
- centerMapOnLocation(dataSet.location(), dataSet.zoomLevel());
+ centerMapOnBounds(dataSet.bounds());
}
}
@@ -184,6 +178,11 @@ private void switchDataSet(String label) {
public void onMapReady(@NonNull GoogleMap googleMap) {
this.map = googleMap;
+ googleMap.setOnCameraIdleListener(() -> {
+ com.google.android.gms.maps.model.CameraPosition cp = googleMap.getCameraPosition();
+ Log.i(TAG, "CAMERA_PARAMS: target=LatLng(" + cp.target.latitude + ", " + cp.target.longitude + "), zoom=" + cp.zoom + "f, tilt=" + cp.tilt + "f, bearing=" + cp.bearing + "f");
+ });
+
MapCapabilities capabilities = map.getMapCapabilities();
Log.d(TAG, "Data-driven Styling is available: " + capabilities.isDataDrivenStylingAvailable());
if (!capabilities.isDataDrivenStylingAvailable()) {
@@ -364,8 +363,8 @@ private void styleBoulderDatasetLayer() {
}
- private void centerMapOnLocation(LatLng location, float zoomLevel) {
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, zoomLevel));
+ private void centerMapOnBounds(LatLngBounds bounds) {
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 80));
}
@Override
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
index 3d54aa420..a1cb5af9f 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
@@ -1,4 +1,4 @@
-// Copyright 2020 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
import com.google.android.gms.maps.model.GroundOverlay;
import com.google.android.gms.maps.model.GroundOverlayOptions;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import android.graphics.Point;
import android.os.Bundle;
@@ -51,6 +52,10 @@ public class GroundOverlayDemoActivity extends SamplesBaseActivity
private static final LatLng NEWARK = new LatLng(40.714086, -74.228697);
private static final LatLng NEAR_NEWARK =
new LatLng(NEWARK.latitude - 0.001, NEWARK.longitude - 0.025);
+ static final LatLngBounds OVERLAY_BOUNDS = new LatLngBounds(
+ new LatLng(40.7050, -74.2600),
+ new LatLng(40.7800, -74.1200)
+ );
private final List images = new ArrayList<>();
@@ -84,7 +89,7 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(binding.getRoot());
binding.transparencySeekBar.setMax(TRANSPARENCY_MAX);
- binding.transparencySeekBar.setProgress(0);
+ binding.transparencySeekBar.setProgress(25);
// Set up programmatic click listeners for the buttons.
binding.switchImage.setOnClickListener(v -> switchImage());
@@ -106,10 +111,8 @@ public void onMapReady(GoogleMap map) {
// Register a listener to respond to clicks on GroundOverlays.
map.setOnGroundOverlayClickListener(this);
- // Move the camera to the Newark area.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11));
-
- map.moveCamera(CameraUpdateFactory.scrollBy(100f, 100f));
+ // Move the camera to frame the Newark overlays with padding.
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(OVERLAY_BOUNDS, 80));
map.setOnMapClickListener(ll -> {
Point point = mMap.getProjection().toScreenLocation(ll);
@@ -141,7 +144,8 @@ public void onMapReady(GoogleMap map) {
// Add a large overlay at Newark on top of the smaller overlay.
groundOverlay = map.addGroundOverlay(new GroundOverlayOptions()
.image(images.get(currentEntry)).anchor(0, 1)
- .position(NEWARK, 8600f, 6500f));
+ .position(NEWARK, 8600f, 6500f)
+ .transparency((float) binding.transparencySeekBar.getProgress() / (float) TRANSPARENCY_MAX));
groundOverlay.setTag(images.get(currentEntry));
binding.transparencySeekBar.setOnSeekBarChangeListener(this);
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
index 515dfa49c..fb03311dd 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
@@ -1,4 +1,4 @@
-// Copyright 2023 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
package com.example.kotlindemos
import android.graphics.Color
+import androidx.core.graphics.toColorInt
import com.google.android.gms.maps.OnMapReadyCallback
import android.os.Bundle
@@ -27,6 +28,7 @@ import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.model.AdvancedMarkerOptions
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MapCapabilities
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.PinConfig
@@ -137,83 +139,93 @@ class AdvancedMarkersDemoActivity : SamplesBaseActivity(), OnMapReadyCallback {
override fun onMapReady(map: GoogleMap) {
- with(map) {
- moveCamera(CameraUpdateFactory.newLatLngZoom(SINGAPORE, ZOOM_LEVEL))
- }
+ val bounds = LatLngBounds.builder()
+ .include(SINGAPORE)
+ .include(KUALA_LUMPUR)
+ .include(JAKARTA)
+ .include(BANGKOK)
+ .include(MANILA)
+ .include(HO_CHI_MINH_CITY)
+ .build()
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 120))
val capabilities: MapCapabilities = map.mapCapabilities
Log.d(TAG, "are advanced marker enabled?" + capabilities.isAdvancedMarkersAvailable)
- // This sample sets a view as the iconView for the Advanced Marker
- val textView = TextView(this)
- textView.text = "Hello!"
- val advancedMarkerView: Marker? = map.addMarker(
- AdvancedMarkerOptions().position(SINGAPORE).iconView(textView).zIndex(1f)
+ // 1. Custom View as iconView (Framed circular badge with Android logo)
+ val iconImageView = android.widget.ImageView(this).apply {
+ setImageResource(R.drawable.ic_android)
+ setColorFilter("#3DDC84".toColorInt()) // Android Green
+ setBackgroundResource(R.drawable.bg_marker_badge)
+ val padding = (8 * resources.displayMetrics.density).toInt()
+ setPadding(padding, padding, padding, padding)
+ layoutParams = android.view.ViewGroup.LayoutParams(
+ (44 * resources.displayMetrics.density).toInt(),
+ (44 * resources.displayMetrics.density).toInt()
+ )
+ }
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .position(SINGAPORE)
+ .iconView(iconImageView)
+ .title("Singapore (Custom Framed Badge)")
+ .zIndex(1f)
)
- // This uses PinConfig.Builder to create an instance of PinConfig.
- val pinConfigBuilder: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder.setBackgroundColor(Color.MAGENTA)
- val pinConfig: PinConfig = pinConfigBuilder.build()
-
-
- // Use the PinConfig instance to set the icon for AdvancedMarkerOptions.
- val advancedMarkerOptions: AdvancedMarkerOptions =
- AdvancedMarkerOptions().icon(BitmapDescriptorFactory.fromPinConfig(pinConfig))
+ // 2. PinConfig with custom background color
+ val pinConfigMagenta = PinConfig.builder()
+ .setBackgroundColor(Color.MAGENTA)
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigMagenta))
.position(KUALA_LUMPUR)
+ .title("Kuala Lumpur (Magenta Pin)")
+ )
+ // 3. PinConfig with custom border color
+ val pinConfigBorder = PinConfig.builder()
+ .setBorderColor(Color.BLUE)
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigBorder))
+ .position(JAKARTA)
+ .title("Jakarta (Blue Border)")
+ )
- // Pass the AdvancedMarkerOptions instance to addMarker().
- val marker: Marker? = map.addMarker(advancedMarkerOptions)
-
- // This sample changes the border color of the advanced marker
- val pinConfigBuilder2: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder2.setBorderColor(Color.BLUE)
- val pinConfig2: PinConfig = pinConfigBuilder2.build()
-
- val advancedMarkerOptions2: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig2))
- .position(JAKARTA)
-
-
- val marker2: Marker? = map.addMarker(advancedMarkerOptions2)
-
- // Set the glyph text.
- val pinConfigBuilder3: PinConfig.Builder = PinConfig.builder()
- val glyphText = PinConfig.Glyph("A")
-
- // Alternatively, you can set the text color:
- // Glyph glyphText = new Glyph("A", Color.GREEN);
- pinConfigBuilder3.setGlyph(glyphText)
- val pinConfig3: PinConfig = pinConfigBuilder3.build()
-
- val advancedMarkerOptions3: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig3))
- .position(BANGKOK)
-
- val marker3: Marker? = map.addMarker(advancedMarkerOptions3)
-
- // Create a transparent glyph.
- val pinConfigBuilder4: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder4.setBackgroundColor(Color.MAGENTA)
- pinConfigBuilder4.setGlyph(PinConfig.Glyph(Color.TRANSPARENT))
- val pinConfig4: PinConfig = pinConfigBuilder4.build()
-
- val advancedMarkerOptions4: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig4))
- .position(MANILA)
+ // 4. PinConfig with text glyph ("A")
+ val pinConfigTextGlyph = PinConfig.builder()
+ .setGlyph(PinConfig.Glyph("A"))
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigTextGlyph))
+ .position(BANGKOK)
+ .title("Bangkok (Text Glyph 'A')")
+ )
- val marker4: Marker? = map.addMarker(advancedMarkerOptions4)
+ // 5. PinConfig with transparent glyph (cutout / donut pin)
+ val pinConfigHole = PinConfig.builder()
+ .setBackgroundColor(Color.MAGENTA)
+ .setGlyph(PinConfig.Glyph(Color.TRANSPARENT))
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigHole))
+ .position(MANILA)
+ .title("Manila (Transparent Cutout Glyph)")
+ )
- // Collision behavior can only be changed in the AdvancedMarkerOptions object.
- // Changes to collision behavior after a marker has been created are not possible
- val collisionBehavior: Int =
+ // 6. Collision behavior
+ val collisionBehavior =
AdvancedMarkerOptions.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL
- val advancedMarkerOptions5: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .position(HO_CHI_MINH_CITY)
- .collisionBehavior(collisionBehavior)
-
- val marker5: Marker? = map.addMarker(advancedMarkerOptions5)
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .position(HO_CHI_MINH_CITY)
+ .collisionBehavior(collisionBehavior)
+ .title("Ho Chi Minh City (Collision Behavior)")
+ )
}
}
// [END maps_android_sample_marker_advanced]
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
index 62656c2f4..1f1443377 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
@@ -1,4 +1,4 @@
-// Copyright 2025 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import android.widget.LinearLayout
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.annotation.ColorInt
+import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.GoogleMap
@@ -39,6 +40,7 @@ import com.google.android.gms.maps.model.FeatureLayerOptions
import com.google.android.gms.maps.model.FeatureStyle
import com.google.android.gms.maps.model.FeatureType
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MapCapabilities
import androidx.core.view.WindowCompat
import com.google.android.gms.maps.GoogleMapOptions
@@ -55,7 +57,6 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
private lateinit var mapContainer: ViewGroup
private lateinit var map: GoogleMap
- private val zoomLevel = 13.5f
private var datasetLayer: FeatureLayer? = null
@@ -64,7 +65,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
private data class DataSet(
val datasetId: String,
- val location: LatLng,
+ val bounds: LatLngBounds,
val callback: DataDrivenDatasetStylingActivity.() -> Unit
)
@@ -86,9 +87,27 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
if (dataSets.isEmpty()) {
with(dataSets) {
- put(getString(com.example.common_ui.R.string.boulder), DataSet(BuildConfig.BOULDER_DATASET_ID, LatLng(40.0150, -105.2705)) { styleBoulderDataset() })
- put(getString(com.example.common_ui.R.string.new_york), DataSet(BuildConfig.NEW_YORK_DATASET_ID, LatLng(40.786244, -73.962684)) { styleNYCDataset() })
- put(getString(com.example.common_ui.R.string.kyoto), DataSet(BuildConfig.KYOTO_DATASET_ID, LatLng(35.005081, 135.764385)) { styleKyotoDataset() })
+ put(
+ getString(com.example.common_ui.R.string.boulder),
+ DataSet(
+ BuildConfig.BOULDER_DATASET_ID,
+ LatLngBounds(LatLng(39.920, -105.340), LatLng(40.090, -105.210))
+ ) { styleBoulderDataset() }
+ )
+ put(
+ getString(com.example.common_ui.R.string.new_york),
+ DataSet(
+ BuildConfig.NEW_YORK_DATASET_ID,
+ LatLngBounds(LatLng(40.7640, -73.9820), LatLng(40.8000, -73.9490))
+ ) { styleNYCDataset() }
+ )
+ put(
+ getString(com.example.common_ui.R.string.kyoto),
+ DataSet(
+ BuildConfig.KYOTO_DATASET_ID,
+ LatLngBounds(LatLng(34.9700, 135.7200), LatLng(35.0400, 135.8000))
+ ) { styleKyotoDataset() }
+ )
}
}
@@ -124,7 +143,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
buttonLayout = findViewById(com.example.common_ui.R.id.button_kyoto).parent as LinearLayout
handleCutout()
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
}
private fun handleCutout() {
@@ -139,6 +158,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}
} else {
window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
+ @Suppress("DEPRECATION")
val topInset = windowInsets.systemWindowInsetTop
mapContainer.setPadding(0, topInset, 0, 0)
windowInsets
@@ -170,7 +190,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}.build()
)
dataSet.callback(this)
- centerMapOnLocation(dataSet.location)
+ centerMapOnBounds(dataSet.bounds)
} ?: run {
Toast.makeText(this, "Unknown dataset: $label", Toast.LENGTH_SHORT).show()
}
@@ -179,6 +199,11 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
+ googleMap.setOnCameraIdleListener {
+ val cp = googleMap.cameraPosition
+ Log.i(TAG, "CAMERA_PARAMS: target=LatLng(${cp.target.latitude}, ${cp.target.longitude}), zoom=${cp.zoom}f, tilt=${cp.tilt}f, bearing=${cp.bearing}f")
+ }
+
val capabilities: MapCapabilities = map.mapCapabilities
println("Data-driven Styling is available: " + capabilities.isDataDrivenStylingAvailable)
@@ -197,7 +222,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
val largePointRadius = 8F
val smallPointRadius = 6F
- val darkRedBrown = resources.getColor(R.color.darkRedBrown)
+ val darkRedBrown = ContextCompat.getColor(this, R.color.darkRedBrown)
val styleFactory = FeatureLayer.StyleFactory { feature: Feature ->
if (feature is DatasetFeature) {
@@ -337,8 +362,8 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}
- private fun centerMapOnLocation(location: LatLng) {
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, zoomLevel))
+ private fun centerMapOnBounds(bounds: LatLngBounds, padding: Int = 80) {
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding))
}
// Define the click event handler to set lastGlobalId to globalid of selected feature.
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
index 8a1e77734..4ee725646 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
@@ -1,4 +1,4 @@
-// Copyright 2020 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.GroundOverlay
import com.google.android.gms.maps.model.GroundOverlayOptions
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
/**
* This demo shows how to add a ground overlay to a map.
@@ -63,7 +64,7 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
setContentView(binding.root)
binding.transparencySeekBar.max = TRANSPARENCY_MAX
- binding.transparencySeekBar.progress = 0
+ binding.transparencySeekBar.progress = 25
// Set up programmatic click listeners for the buttons.
// This is a better practice than using the android:onClick XML attribute, as it keeps
@@ -90,10 +91,8 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
// Register a listener to respond to clicks on GroundOverlays.
map.setOnGroundOverlayClickListener(this)
- // Move the camera to the Newark area.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11f))
-
- map.moveCamera(CameraUpdateFactory.scrollBy(100f, 100f))
+ // Move the camera to frame the Newark overlays with padding.
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(OVERLAY_BOUNDS, 80))
// Prepare the BitmapDescriptor objects. Using a BitmapDescriptorFactory is the most
// memory-efficient way to create the images that will be used for the overlays.
@@ -124,6 +123,7 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
GroundOverlayOptions()
.image(images[currentEntry]).anchor(0f, 1f)
.position(NEWARK, 8600f, 6500f)
+ .transparency(binding.transparencySeekBar.progress.toFloat() / TRANSPARENCY_MAX.toFloat())
) ?: error("Expected a non null addGroundOverlay")
groundOverlay.tag = images[currentEntry]
@@ -187,5 +187,9 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
NEWARK.latitude - 0.001,
NEWARK.longitude - 0.025
)
+ internal val OVERLAY_BOUNDS = LatLngBounds(
+ LatLng(40.7050, -74.2600),
+ LatLng(40.7800, -74.1200)
+ )
}
}
\ No newline at end of file