Skip to content

Commit c156e51

Browse files
committed
feat: implement Java sample parity, animations, and interaction handlers
- Implement verified Java sample parity fixes across Camera, VisibleRegion, Marker, Boundaries, DatasetStyling, CloudStyling, GroundOverlay, and TileOverlay - Simulate Fowler / Rattlesnake GPX track and add modern runtime permission launcher in LocationSourceDemoActivity - Polish layouts, touch targets, and coordinate displays across Java sample activities
1 parent d9bc7d6 commit c156e51

25 files changed

Lines changed: 830 additions & 130 deletions

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/AdvancedMarkersDemoActivity.java‎

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
// limitations under the License.
1414
package com.example.mapdemo;
1515

16+
import com.example.common_ui.catalog.Sample;
17+
import com.example.common_ui.catalog.Complexity;
18+
import com.example.common_ui.catalog.Framework;
19+
1620
import android.graphics.Color;
1721
import android.os.Bundle;
1822
import android.util.Log;
@@ -46,6 +50,18 @@
4650
* possibilities.
4751
*/
4852
// [START maps_android_sample_marker_advanced]
53+
@Sample(
54+
id = "advanced_markers",
55+
title = "Advanced Markers & Pins",
56+
description = "Modern PinConfig pins, custom glyphs, badge icon views, and collision behavior.",
57+
category = "Markers & Overlays",
58+
complexity = Complexity.ADVANCED,
59+
tags = {"#markers", "#advancedmarkers", "#pinconfig", "#collision", "#badges", "#mapid"},
60+
purpose = "Demonstrates Cloud-backed Advanced Markers with custom colors, pin glyphs, collision behaviors, and custom View icons.",
61+
successCriteria = "Custom colored pins and badge icon views render sharply at correct anchor points with collision handling.",
62+
failureIndicators = "Pins render as default red markers (missing Map ID), collision behavior ignored, or badge text blurry.",
63+
framework = Framework.JAVA_VIEWS
64+
)
4965
public class AdvancedMarkersDemoActivity extends SamplesBaseActivity implements OnMapReadyCallback {
5066

5167
private static final LatLng SINGAPORE = new LatLng(1.3521, 103.8198);
@@ -152,13 +168,17 @@ public void onMapReady(GoogleMap map) {
152168
pinConfigBuilder.setBackgroundColor(Color.MAGENTA);
153169
PinConfig pinConfig = pinConfigBuilder.build();
154170

155-
// Use the PinConfig instance to set the icon for AdvancedMarkerOptions.
171+
// Use the PinConfig instance to set the icon for AdvancedMarkerOptions.
156172
AdvancedMarkerOptions advancedMarkerOptions = new AdvancedMarkerOptions()
157173
.icon(BitmapDescriptorFactory.fromPinConfig(pinConfig))
158-
.position(KUALA_LUMPUR);
174+
.position(KUALA_LUMPUR)
175+
.title("Kuala Lumpur (Magenta Pin)");
159176

160177
// Pass the AdvancedMarkerOptions instance to addMarker().
161178
Marker marker = map.addMarker(advancedMarkerOptions);
179+
if (marker != null) {
180+
marker.showInfoWindow();
181+
}
162182

163183
// This sample changes the border color of the advanced marker
164184
PinConfig.Builder pinConfigBuilder2 = PinConfig.builder();
@@ -167,7 +187,8 @@ public void onMapReady(GoogleMap map) {
167187

168188
AdvancedMarkerOptions advancedMarkerOptions2 = new AdvancedMarkerOptions()
169189
.icon(BitmapDescriptorFactory.fromPinConfig(pinConfig2))
170-
.position(JAKARTA);
190+
.position(JAKARTA)
191+
.title("Jakarta (Blue Border)");
171192

172193
Marker marker2 = map.addMarker(advancedMarkerOptions2);
173194

@@ -182,7 +203,8 @@ public void onMapReady(GoogleMap map) {
182203

183204
AdvancedMarkerOptions advancedMarkerOptions3 = new AdvancedMarkerOptions()
184205
.icon(BitmapDescriptorFactory.fromPinConfig(pinConfig3))
185-
.position(BANGKOK);
206+
.position(BANGKOK)
207+
.title("Bangkok (Text Glyph 'A')");
186208

187209
Marker marker3 = map.addMarker(advancedMarkerOptions3);
188210

@@ -194,7 +216,8 @@ public void onMapReady(GoogleMap map) {
194216

195217
AdvancedMarkerOptions advancedMarkerOptions4 = new AdvancedMarkerOptions()
196218
.icon(BitmapDescriptorFactory.fromPinConfig(pinConfig4))
197-
.position(MANILA);
219+
.position(MANILA)
220+
.title("Manila (Transparent Cutout Glyph)");
198221

199222
Marker marker4 = map.addMarker(advancedMarkerOptions4);
200223

@@ -203,7 +226,8 @@ public void onMapReady(GoogleMap map) {
203226
int collisionBehavior = AdvancedMarkerOptions.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL;
204227
AdvancedMarkerOptions advancedMarkerOptions5 = new AdvancedMarkerOptions()
205228
.position(HO_CHI_MINH_CITY)
206-
.collisionBehavior(collisionBehavior);
229+
.collisionBehavior(collisionBehavior)
230+
.title("Ho Chi Minh City (Collision Behavior)");
207231

208232
Marker marker5 = map.addMarker(advancedMarkerOptions5);
209233
}

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/BasicMapDemoActivity.java‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
package com.example.mapdemo;
1616

17+
import com.example.common_ui.catalog.Sample;
18+
import com.example.common_ui.catalog.Complexity;
19+
import com.example.common_ui.catalog.Framework;
20+
21+
import com.google.android.gms.maps.CameraUpdateFactory;
1722
import com.google.android.gms.maps.GoogleMap;
1823
import com.google.android.gms.maps.OnMapReadyCallback;
1924
import com.google.android.gms.maps.SupportMapFragment;
@@ -28,8 +33,28 @@
2833
* This shows how to create a simple activity with a map and a marker on the map.
2934
*/
3035
// [START maps_android_sample_basic_map]
36+
@Sample(
37+
id = "basic_map",
38+
title = "Basic Map",
39+
description = "Fundamental map instantiation, lifecycle binding, and default camera centering.",
40+
category = "Map Initialization",
41+
complexity = Complexity.SNIPPET,
42+
tags = {"#map", "#init", "#lifecycle", "#quickstart"},
43+
apiCalls = {
44+
"SupportMapFragment.getMapAsync(OnMapReadyCallback)",
45+
"GoogleMap.addMarker(MarkerOptions)",
46+
"GoogleMap.moveCamera(CameraUpdate)"
47+
},
48+
purpose = "Demonstrates clean, minimal map instantiation using SupportMapFragment.",
49+
successCriteria = "The map loads default vector tiles cleanly centered at the initial coordinates with working gestures.",
50+
failureIndicators = "Grey tiles (missing API key or auth mismatch), crash on back navigation, or map failing to unpause.",
51+
framework = Framework.JAVA_VIEWS
52+
)
3153
public class BasicMapDemoActivity extends SamplesBaseActivity implements OnMapReadyCallback {
3254

55+
private static final LatLng SYDNEY = new LatLng(-33.862, 151.21);
56+
private static final float ZOOM_LEVEL = 13.0f;
57+
3358
@Override
3459
protected void onCreate(Bundle savedInstanceState) {
3560
super.onCreate(savedInstanceState);
@@ -43,12 +68,12 @@ protected void onCreate(Bundle savedInstanceState) {
4368

4469
/**
4570
* This is where we can add markers or lines, add listeners or move the camera. In this case,
46-
* we
47-
* just add a marker near Africa.
71+
* we move the camera to Sydney and add a marker at Sydney.
4872
*/
4973
@Override
5074
public void onMapReady(GoogleMap map) {
51-
map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
75+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, ZOOM_LEVEL));
76+
map.addMarker(new MarkerOptions().position(SYDNEY).title("Sydney"));
5277
}
5378
}
5479
// [END maps_android_sample_basic_map]

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraClampingDemoActivity.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
package com.example.mapdemo;
1717

18+
import com.example.common_ui.catalog.Sample;
19+
import com.example.common_ui.catalog.Complexity;
20+
import com.example.common_ui.catalog.Framework;
21+
1822
import com.google.android.gms.maps.CameraUpdateFactory;
1923
import com.google.android.gms.maps.GoogleMap;
2024
import com.google.android.gms.maps.GoogleMap.OnCameraIdleListener;
@@ -30,6 +34,18 @@
3034
/**
3135
* This shows how to constrain the camera to specific boundaries and zoom levels.
3236
*/
37+
@Sample(
38+
id = "camera_clamping",
39+
title = "Camera Clamping & Bounds",
40+
description = "Constraining camera viewport to LatLngBounds and dynamic min/max zoom limits.",
41+
category = "Camera Controls",
42+
complexity = Complexity.SIMPLE,
43+
tags = {"#camera", "#clamping", "#bounds", "#zoomlimits", "#latlngbounds"},
44+
purpose = "Demonstrates restricting camera panning to a specific bounding box (Adelaide/Pacific) and zoom slider limits.",
45+
successCriteria = "User cannot pan the camera outside the clamped region; zoom sliders enforce min/max bounds immediately.",
46+
failureIndicators = "Camera pans outside bounding box or resetting bounds fails when selecting 'Reset Bounds'.",
47+
framework = Framework.JAVA_VIEWS
48+
)
3349
public class CameraClampingDemoActivity extends SamplesBaseActivity
3450
implements OnMapReadyCallback, OnCameraIdleListener, GoogleMap.OnCameraMoveListener {
3551

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraDemoActivity.java‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
package com.example.mapdemo;
1717

18+
import com.example.common_ui.catalog.Sample;
19+
import com.example.common_ui.catalog.Complexity;
20+
import com.example.common_ui.catalog.Framework;
21+
1822
import android.graphics.Color;
1923
import android.os.Bundle;
2024
import android.util.Log;
@@ -37,13 +41,32 @@
3741
import com.google.android.gms.maps.SupportMapFragment;
3842
import com.google.android.gms.maps.model.CameraPosition;
3943
import com.google.android.gms.maps.model.LatLng;
44+
import com.google.android.gms.maps.model.MarkerOptions;
4045
import com.example.common_ui.databinding.CameraDemoBinding;
4146
import com.google.android.gms.maps.model.PolylineOptions;
4247

4348
/**
4449
* This shows how to change the camera position for the map.
4550
*/
4651
// [START maps_camera_events]
52+
@Sample(
53+
id = "camera_demo",
54+
title = "Camera Controls & Animation",
55+
description = "Programmatic camera panning, zooming, tilt, bearing, and smooth animations.",
56+
category = "Camera Controls",
57+
complexity = Complexity.SIMPLE,
58+
tags = {"#camera", "#animation", "#bearing", "#tilt", "#zoom", "#pan"},
59+
apiCalls = {
60+
"GoogleMap.animateCamera(CameraUpdate)",
61+
"GoogleMap.moveCamera(CameraUpdate)",
62+
"GoogleMap.addMarker(MarkerOptions)",
63+
"CameraUpdateFactory.newCameraPosition(CameraPosition)"
64+
},
65+
purpose = "Demonstrates programmatic camera movements, animated transitions, tilt angles, and bearing rotations.",
66+
successCriteria = "Buttons animate camera smoothly with custom durations, stops, and rotation angles.",
67+
failureIndicators = "Jerky animations, unexpected camera jumps, or tilt angle exceeding platform constraints.",
68+
framework = Framework.JAVA_VIEWS
69+
)
4770
public class CameraDemoActivity extends SamplesBaseActivity implements
4871
OnCameraMoveStartedListener,
4972
OnCameraMoveListener,
@@ -140,7 +163,11 @@ public void onMapReady(GoogleMap googleMap) {
140163
// [END_EXCLUDE]
141164

142165
// Show Sydney
143-
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
166+
LatLng sydneyLatLng = new LatLng(-33.87365, 151.20689);
167+
LatLng bondiLatLng = new LatLng(-33.891614, 151.276417);
168+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydneyLatLng, 10));
169+
map.addMarker(new MarkerOptions().position(sydneyLatLng).title("Sydney"));
170+
map.addMarker(new MarkerOptions().position(bondiLatLng).title("Bondi Beach"));
144171
}
145172

146173
public GoogleMap getMap() {

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CircleDemoActivity.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
package com.example.mapdemo;
1616

17+
import com.example.common_ui.catalog.Sample;
18+
import com.example.common_ui.catalog.Complexity;
19+
import com.example.common_ui.catalog.Framework;
20+
1721
import android.graphics.Color;
1822
import android.graphics.Point;
1923
import android.location.Location;
@@ -56,6 +60,18 @@
5660
/**
5761
* This shows how to draw circles on a map.
5862
*/
63+
@Sample(
64+
id = "circles",
65+
title = "Circles & Geodesic Radii",
66+
description = "Drawing geographic circles with dynamic center drag, radius sliders, and stroke styling.",
67+
category = "Shapes & Geometry",
68+
complexity = Complexity.SIMPLE,
69+
tags = {"#shapes", "#circles", "#radius", "#geodesic"},
70+
purpose = "Demonstrates drawing circles with radius defined in meters and dynamic updates via seekbars.",
71+
successCriteria = "Adjusting radius slider dynamically updates circle boundary in real-time.",
72+
failureIndicators = "Circle distorted or radius math inaccurate across high latitudes.",
73+
framework = Framework.JAVA_VIEWS
74+
)
5975
public class CircleDemoActivity extends SamplesBaseActivity
6076
implements OnSeekBarChangeListener, OnMarkerDragListener, OnMapLongClickListener,
6177
OnItemSelectedListener, OnMapReadyCallback, MapProvider {

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CloudBasedMapStylingDemoActivity.java‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
import android.os.Bundle;
1818
import androidx.appcompat.app.AppCompatActivity;
19+
import com.example.common_ui.R;
20+
import com.google.android.gms.maps.CameraUpdateFactory;
1921
import com.google.android.gms.maps.GoogleMap;
2022
import com.google.android.gms.maps.OnMapReadyCallback;
2123
import com.google.android.gms.maps.SupportMapFragment;
24+
import com.google.android.gms.maps.model.LatLng;
2225

2326
/**
2427
* This shows how to use Cloud-based Map Styling in a simple Activity. For more information on how
@@ -40,29 +43,31 @@ protected void onCreate(Bundle savedInstanceState) {
4043

4144
// The underlying style the map will use has been set in the layout
4245
// `cloud_styling_basic_demo` under the SupportMapFragment's `map:mapId` attribute.
43-
setContentView(com.example.common_ui.R.layout.cloud_styling_basic_demo);
46+
setContentView(R.layout.cloud_styling_basic_demo);
4447
SupportMapFragment mapFragment =
45-
(SupportMapFragment) getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map);
48+
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
4649
mapFragment.getMapAsync(this);
4750

4851
setUpButtonListeners();
49-
applyInsets(findViewById(com.example.common_ui.R.id.map_container));
52+
applyInsets(findViewById(R.id.map_container));
5053
}
5154

5255
@Override
5356
public void onMapReady(GoogleMap map) {
5457
this.map = map;
5558
map.setMapType(currentMapType);
59+
LatLng montBlanc = new LatLng(45.8326, 6.8652);
60+
map.moveCamera(CameraUpdateFactory.newLatLngZoom(montBlanc, 11.5f));
5661
}
5762

5863
private void setUpButtonListeners() {
59-
findViewById(com.example.common_ui.R.id.styling_normal_mode).setOnClickListener(
64+
findViewById(R.id.styling_normal_mode).setOnClickListener(
6065
v -> setMapType(GoogleMap.MAP_TYPE_NORMAL));
61-
findViewById(com.example.common_ui.R.id.styling_satellite_mode).setOnClickListener(
66+
findViewById(R.id.styling_satellite_mode).setOnClickListener(
6267
v -> setMapType(GoogleMap.MAP_TYPE_SATELLITE));
63-
findViewById(com.example.common_ui.R.id.styling_hybrid_mode).setOnClickListener(
68+
findViewById(R.id.styling_hybrid_mode).setOnClickListener(
6469
v -> setMapType(GoogleMap.MAP_TYPE_HYBRID));
65-
findViewById(com.example.common_ui.R.id.styling_terrain_mode).setOnClickListener(
70+
findViewById(R.id.styling_terrain_mode).setOnClickListener(
6671
v -> setMapType(GoogleMap.MAP_TYPE_TERRAIN));
6772
}
6873

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenBoundariesActivity.java‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
// limitations under the License.
1414
package com.example.mapdemo;
1515

16+
import com.example.common_ui.catalog.Sample;
17+
import com.example.common_ui.catalog.Complexity;
18+
import com.example.common_ui.catalog.Framework;
19+
1620
import static java.lang.Math.round;
1721

1822
import android.graphics.Color;
@@ -58,6 +62,18 @@
5862
* https://developers.google.com/maps/documentation/android-sdk/dds-boundaries/overview
5963
*/
6064
// [START maps_android_data_driven_styling_boundaries]
65+
@Sample(
66+
id = "data_driven_boundaries",
67+
title = "Data-Driven Boundaries",
68+
description = "Dynamic styling and click handlers for administrative boundaries (Localities, States, Countries).",
69+
category = "Data-Driven Styling",
70+
complexity = Complexity.ADVANCED,
71+
tags = {"#boundaries", "#datadriven", "#featurelayer", "#locality", "#choropleth"},
72+
purpose = "Demonstrates styling administrative boundaries dynamically via FeatureLayer and capturing boundary clicks.",
73+
successCriteria = "Boundaries render with custom stroke and fill colors; tapping a region highlights its polygon.",
74+
failureIndicators = "Boundary layer is null (requires vector map / Map ID) or click listener not firing.",
75+
framework = Framework.JAVA_VIEWS
76+
)
6177
public class DataDrivenBoundariesActivity extends SamplesBaseActivity implements OnMapReadyCallback,
6278
FeatureLayer.OnFeatureClickListener, PopupMenu.OnMenuItemClickListener {
6379
private static final String TAG = DataDrivenBoundariesActivity.class.getName();
@@ -119,8 +135,16 @@ protected void onCreate(Bundle savedInstanceState) {
119135

120136
mapFragment.getMapAsync(this);
121137

122-
findViewById(R.id.button_hawaii).setOnClickListener(view -> centerMapOnLocation(HANA_HAWAII, 11f));
123-
findViewById(R.id.button_us).setOnClickListener(view -> centerMapOnLocation(CENTER_US, 1f));
138+
findViewById(R.id.button_hawaii).setOnClickListener(view -> {
139+
localityEnabled = true;
140+
updateStyles();
141+
centerMapOnLocation(HANA_HAWAII, 11f);
142+
});
143+
findViewById(R.id.button_us).setOnClickListener(view -> {
144+
adminAreaEnabled = true;
145+
updateStyles();
146+
centerMapOnLocation(CENTER_US, 3.8f);
147+
});
124148

125149
applyInsets(findViewById(R.id.map_container));
126150

‎ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
// limitations under the License.
1414
package com.example.mapdemo;
1515

16+
import com.example.common_ui.catalog.Sample;
17+
import com.example.common_ui.catalog.Complexity;
18+
import com.example.common_ui.catalog.Framework;
19+
1620
import android.graphics.Color;
1721
import android.os.Bundle;
1822
import android.util.Log;
@@ -55,6 +59,18 @@
5559
* This is meant to work with the datasets in the res/raw directory.
5660
*/
5761
// [START maps_android_data_driven_styling_datasets]
62+
@Sample(
63+
id = "data_driven_datasets",
64+
title = "Data-Driven Dataset Styling",
65+
description = "Styling custom geospatial datasets uploaded to Google Cloud Platform based on attributes.",
66+
category = "Data-Driven Styling",
67+
complexity = Complexity.ADVANCED,
68+
tags = {"#datasets", "#datadriven", "#clouddata", "#attributes", "#filtering"},
69+
purpose = "Demonstrates loading a Cloud Dataset FeatureLayer and applying dynamic style rules based on feature properties.",
70+
successCriteria = "Dataset points and polygons display distinct styling according to attribute values.",
71+
failureIndicators = "Dataset ID invalid or attributes fail to filter correctly.",
72+
framework = Framework.JAVA_VIEWS
73+
)
5874
public class DataDrivenDatasetStylingActivity extends SamplesBaseActivity implements OnMapReadyCallback, FeatureLayer.OnFeatureClickListener {
5975
private record DataSet(
6076
String label,

0 commit comments

Comments
 (0)