Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b6a6c8f
feat: create repo-root catalog, basic Compose map sample, and establi…
dkhawk Apr 3, 2026
43e4f03
feat: initialize ComposeDemos module and reorganize catalog
dkhawk Apr 23, 2026
00652cd
feat: add Polylines sample data, tests, and screenshot
dkhawk Apr 23, 2026
c71f07a
docs: use HTML img tags for catalog thumbnails
dkhawk Apr 23, 2026
70a5638
feat: implement Popovers sample and visual test
dkhawk Apr 23, 2026
c8b6286
feat: apply immersive mode and update catalog thumbnails
dkhawk Apr 23, 2026
9a5ab2e
feat: implement Polygons, Models, and Markers samples
dkhawk Apr 23, 2026
ab7f9fe
fix: correct spelling of Visualization to American English
dkhawk Apr 23, 2026
c9eed08
feat: implement Camera Restrictions sample and visual test
dkhawk Apr 23, 2026
f8e55c8
style: run spotlessApply to format code
dkhawk Apr 23, 2026
bd0cdb9
style: clean up fully qualified names and format code
dkhawk Apr 23, 2026
72765dc
feat: implement missing compose samples and fix library bugs
dkhawk Apr 23, 2026
5cd4041
chore: add default API key placeholders to local.defaults.properties
dkhawk Apr 23, 2026
29e4408
feat(samples): align Java and Kotlin camera controls and improve cata…
dkhawk Apr 27, 2026
587139d
feat(samples): implement Map Interactions and add visual tests for Ja…
dkhawk May 20, 2026
51c6652
Merge branch 'origin/main' into feat/catalogs-for-java-and-kotlin-views
dkhawk May 20, 2026
c3c3c57
refactor(samples): implement robust isInitialized delayed fallback pa…
dkhawk May 20, 2026
23caccf
test(api-demos): stabilize visual testing suite and fix rendering gli…
dkhawk May 20, 2026
0559073
test(api-demos): update activity copyright headers to 2026
dkhawk May 20, 2026
cc7600f
fix(api-demos): resolve hardcoded string lint warnings in map interac…
dkhawk May 20, 2026
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
172 changes: 172 additions & 0 deletions Maps3DSamples/ApiDemos/catalog_automation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import subprocess
import os
import sys
import re

def run_command(cmd, cwd=None):
print(f"Running: {cmd}")
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=cwd)
if result.returncode != 0:
print(f"Command failed with exit code {result.returncode}")
print(result.stderr)
return False, result.stdout
return True, result.stdout

def main():
if len(sys.argv) < 3:
print("Usage: python3 catalog_automation.py <java|kotlin> <TestClassName>")
sys.exit(1)

app_type = sys.argv[1]
test_class = sys.argv[2]

if app_type not in ["java", "kotlin"]:
print("Invalid app type. Use 'java' or 'kotlin'.")
sys.exit(1)

# Workspace root relative to this script
script_dir = os.path.dirname(os.path.abspath(__file__))
workspace_root = os.path.abspath(os.path.join(script_dir, "../.."))

package_mapping = {
"java": "com.example.maps3djava",
"kotlin": "com.example.maps3dkotlin"
}
package = package_mapping[app_type]

module_mapping = {
"java": ":Maps3DSamples:ApiDemos:java-app",
"kotlin": ":Maps3DSamples:ApiDemos:kotlin-app"
}
module = module_mapping[app_type]

# 1. Install and Run Test
print(f"Installing {app_type} app...")
success, _ = run_command(f"./gradlew {module}:installDebug", cwd=workspace_root)
if not success: sys.exit(1)

print(f"Installing {app_type} test app...")
success, _ = run_command(f"./gradlew {module}:installDebugAndroidTest", cwd=workspace_root)
if not success: sys.exit(1)

print("Running test...")
cmd = f"adb shell am instrument -w -e class {package}.{test_class} {package}.test/androidx.test.runner.AndroidJUnitRunner"
success, output = run_command(cmd, cwd=workspace_root)
if not success:
print("Test failed.")
sys.exit(1)

print("Test passed. Pulling screenshot...")

# 2. Pull Screenshot
filename_mapping = {
"HelloMapVisualTest": "hello_map_screenshot.png",
"PolylinesVisualTest": "polylines_screenshot.png",
"MapInteractionsVisualTest": "map_interactions_screenshot.png",
"PopoversVisualTest": "popovers_screenshot.png",
"CameraControlsVisualTest": "camera_controls_screenshot.png",
"PolygonsVisualTest": "polygons_screenshot.png",
"ModelsVisualTest": "models_screenshot.png",
"MarkersVisualTest": "markers_screenshot.png",
}

filename = filename_mapping.get(test_class, f"{test_class.lower()}_screenshot.png")
local_path = filename

# Use run-as to read the file from the app's data directory and pipe it to a local file
cat_cmd = f"adb shell run-as {package} cat files/{filename}"
print(f"Running: {cat_cmd}")
result = subprocess.run(cat_cmd, shell=True, capture_output=True, text=False)
if result.returncode != 0:
print(f"Failed to read screenshot via run-as. Error: {result.stderr.decode('utf-8')}")
sys.exit(1)

with open(local_path, "wb") as f:
f.write(result.stdout)
print(f"Pulled screenshot to {local_path}")

# 3. Scale Image using sips (macOS built-in)
dim_cmd = f"sips -g pixelWidth -g pixelHeight {local_path}"
success, dim_output = run_command(dim_cmd)
if not success:
print("Failed to get image dimensions.")
sys.exit(1)

try:
width = int(re.search(r"pixelWidth: (\d+)", dim_output).group(1))
height = int(re.search(r"pixelHeight: (\d+)", dim_output).group(1))
except AttributeError:
print(f"Failed to parse dimensions from output: {dim_output}")
sys.exit(1)

new_width = int(width * 0.5)
new_height = int(height * 0.5)

print(f"Scaling from {width}x{height} to {new_width}x{new_height}")
scale_cmd = f"sips -z {new_height} {new_width} {local_path}"
success, _ = run_command(scale_cmd)
if not success:
print("Failed to scale image.")
sys.exit(1)

# 4. Move to Source
app_dir_mapping = {
"java": "java-app",
"kotlin": "kotlin-app"
}
app_dir = app_dir_mapping[app_type]
target_dir = f"{workspace_root}/Maps3DSamples/ApiDemos/{app_dir}/screenshots"
os.makedirs(target_dir, exist_ok=True)

target_path = f"{target_dir}/{local_path}"
os.rename(local_path, target_path)
print(f"Screenshot saved to {target_path}")

# 5. Update Catalog
catalog_path = f"{workspace_root}/Maps3DSamples/ApiDemos/{app_dir}/README.md"

mapping = {
"HelloMapVisualTest": "Basic Map",
"PolylinesVisualTest": "Polylines",
"MapInteractionsVisualTest": "Map Interactions",
"PopoversVisualTest": "Popovers",
"CameraControlsVisualTest": "Camera Controls",
"PolygonsVisualTest": "Polygons",
"ModelsVisualTest": "Models",
"MarkersVisualTest": "Markers",
}

feature_name = mapping.get(test_class)
if feature_name:
if not os.path.exists(catalog_path):
print(f"Catalog file not found: {catalog_path}")
sys.exit(1)

with open(catalog_path, "r") as f:
catalog_content = f.read()

image_link = f'<img src="screenshots/{local_path}" alt="Screenshot" width="121"/>'

lines = catalog_content.split("\n")
updated = False
for i, line in enumerate(lines):
if f"| **{feature_name}** |" in line:
parts = line.split("|")
if len(parts) >= 5:
parts[4] = f" {image_link} "
lines[i] = "|".join(parts)
updated = True
break

if updated:
catalog_content = "\n".join(lines)
with open(catalog_path, "w") as f:
f.write(catalog_content)
print(f"Updated Catalog README.md for {feature_name}")
else:
print(f"Feature {feature_name} not found in catalog.")
else:
print(f"No mapping found for {test_class} in catalog.")

if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
android:id="@+id/map3dView"
map3d:mapId="bcce776b92de1336e22c569f"
map3d:mode="hybrid"
map3d:centerLat="40.748392"
map3d:centerLng="-73.986060"
map3d:centerAlt="175"
map3d:heading="26"
map3d:tilt="67"
map3d:range="4000"
map3d:centerLat="38.743498"
map3d:centerLng="-109.499307"
map3d:centerAlt="1467"
map3d:heading="151"
map3d:tilt="68"
map3d:range="250"
map3d:roll="0"
map3d:minAltitude="0"
map3d:maxAltitude="1000000"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map3d="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#80BB86FC"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:elevation="0dp"
>

<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_bar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:title="Map Interactions"
app:titleTextColor="@android:color/white"
/>
</com.google.android.material.appbar.AppBarLayout>

<com.google.android.gms.maps3d.Map3DView
android:id="@+id/map3dView"
map3d:mode="hybrid"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

<TextView
android:id="@+id/clicked_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:background="#CCFFFFFF"
android:padding="16dp"
android:text="@string/map_interactions_clicked_info"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:contentDescription="@string/map_interactions_clicked_info"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_bar"
style="@style/Widget.MaterialComponents.Toolbar.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleTextColor="?attr/colorOnPrimary"
android:fitsSystemWindows="true"
/>

<TextView
android:id="@+id/skeleton_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/feature_not_implemented"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/top_bar"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
17 changes: 16 additions & 1 deletion Maps3DSamples/ApiDemos/common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@
<string name="feature_title_polylines">Polylines</string>
<string name="feature_title_3d_models">3D models</string>
<string name="feature_title_popovers">Popovers</string>
<string name="feature_title_camera_restrictions">Camera Restrictions</string>
<string name="feature_title_flight_simulator">Flight Simulator</string>
<string name="feature_title_routes_api">Routes API</string>
<string name="feature_title_path_following">Path Following</string>
<string name="feature_title_path_styling">Path Styling</string>
<string name="feature_title_animating_models">Animating Models</string>
<string name="feature_title_place_search">Place Search</string>
<string name="feature_title_place_autocomplete">Place Autocomplete</string>
<string name="feature_title_place_details">Place Details</string>
<string name="feature_title_advanced_camera_animation">Advanced Camera Animation</string>
<string name="feature_title_data_visualization">Data Visualization</string>
<string name="feature_title_cloud_styling">Cloud Map Styling</string>
<string name="feature_title_roadmap_mode">Roadmap Mode</string>
<string name="feature_title_field_of_view">Field Of View</string>

<string name="feature_not_implemented">Coming soon!</string>

Expand Down Expand Up @@ -85,11 +99,12 @@
-->
<string name="in_kilometers" translatable="false">%1$,.1f km</string>

<string name="camera_state_format" formatted="false">Lat: %.4f, Lng: %.4f, Alt: %.2fm\nHdg: %.2f° (%s), Tlt: %.2f°, Rng: %.2fm</string>
<string name="camera_state_format" formatted="false">Lat: %.4f, Lng: %.4f, Alt: %.2fm\nHeading: %.2f° (%s), Tlt: %.2f°, Rng: %.2fm</string>
<string name="polygon_museum_clicked">Check out the Museum!</string>
<string name="polygon_zoo_clicked">Zoo time</string>
<string name="polyline_trail_clicked">Hiking time!</string>
<string name="model_plane_clicked">Model clicked</string>
<string name="map_interactions_clicked_info">Click on the map to see details</string>

<!-- Monster Blurbs -->
<string name="monster_alien_blurb">They didn\'t just come to sculpt mashed potatoes. 👽</string>
Expand Down
35 changes: 25 additions & 10 deletions Maps3DSamples/ApiDemos/java-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,32 @@ This directory contains the Java samples using traditional Android Views for the

## 📊 Sample Status

| Feature | Status | Source Code |
| :--- | :--- | :--- |
| **Hello Map** | ✅ Done | [HelloMapActivity.java](src/main/java/com/example/maps3djava/hellomap/HelloMapActivity.java) |
| **Polylines** | ✅ Done | [PolylinesActivity.java](src/main/java/com/example/maps3djava/polylines/PolylinesActivity.java) |
| **Map Interactions** | ✅ Done | [MapInteractionsActivity.java](src/main/java/com/example/maps3djava/mapinteractions/MapInteractionsActivity.java) |
| **Popovers** | ✅ Done | [PopoversActivity.java](src/main/java/com/example/maps3djava/popovers/PopoversActivity.java) |
| **Camera Controls** | ✅ Done | [CameraControlsActivity.java](src/main/java/com/example/maps3djava/cameracontrols/CameraControlsActivity.java) |
| **Polygons** | ✅ Done | [PolygonsActivity.java](src/main/java/com/example/maps3djava/polygons/PolygonsActivity.java) |
| **Models** | ✅ Done | [ModelsActivity.java](src/main/java/com/example/maps3djava/models/ModelsActivity.java) |
| **Markers** | ✅ Done | [MarkersActivity.java](src/main/java/com/example/maps3djava/markers/MarkersActivity.java) |
| Feature | Status | Source Code | Screenshot |
| :--- | :--- | :--- | :--- |
| **Basic Map** | ✅ Done | [HelloMapActivity.java](src/main/java/com/example/maps3djava/hellomap/HelloMapActivity.java) | <img src="screenshots/hello_map_screenshot.png" alt="Screenshot" width="121"/> |
| **Polylines** | ✅ Done | [PolylinesActivity.java](src/main/java/com/example/maps3djava/polylines/PolylinesActivity.java) | |
| **Map Interactions** | ✅ Done | [MapInteractionsActivity.java](src/main/java/com/example/maps3djava/mapinteractions/MapInteractionsActivity.java) | <img src="screenshots/map_interactions_screenshot.png" alt="Screenshot" width="121"/> |
| **Popovers** | ✅ Done | [PopoversActivity.java](src/main/java/com/example/maps3djava/popovers/PopoversActivity.java) | |
| **Camera Controls** | ✅ Done | [CameraControlsActivity.java](src/main/java/com/example/maps3djava/cameracontrols/CameraControlsActivity.java) | <img src="screenshots/camera_controls_screenshot.png" alt="Screenshot" width="121"/> |
| **Polygons** | ✅ Done | [PolygonsActivity.java](src/main/java/com/example/maps3djava/polygons/PolygonsActivity.java) | |
| **Models** | ✅ Done | [ModelsActivity.java](src/main/java/com/example/maps3djava/models/ModelsActivity.java) | |
| **Markers** | ✅ Done | [MarkersActivity.java](src/main/java/com/example/maps3djava/markers/MarkersActivity.java) | |
| **Camera Restrictions** | 🚧 Skeleton | [CameraRestrictionsActivity.java](src/main/java/com/example/maps3djava/camerarestrictions/CameraRestrictionsActivity.java) | |
| **Flight Simulator** | 🚧 Skeleton | [FlightSimulatorActivity.java](src/main/java/com/example/maps3djava/flightsimulator/FlightSimulatorActivity.java) | |
| **Routes API** | 🚧 Skeleton | [RoutesActivity.java](src/main/java/com/example/maps3djava/routes/RoutesActivity.java) | |
| **Path Following** | 🚧 Skeleton | [PathFollowingActivity.java](src/main/java/com/example/maps3djava/pathfollowing/PathFollowingActivity.java) | |
| **Path Styling** | 🚧 Skeleton | [PathStylingActivity.java](src/main/java/com/example/maps3djava/pathstyling/PathStylingActivity.java) | |
| **Animating Models** | 🚧 Skeleton | [AnimatingModelsActivity.java](src/main/java/com/example/maps3djava/animatingmodels/AnimatingModelsActivity.java) | |
| **Place Search** | 🚧 Skeleton | [PlaceSearchActivity.java](src/main/java/com/example/maps3djava/placesearch/PlaceSearchActivity.java) | |
| **Place Autocomplete** | 🚧 Skeleton | [PlaceAutocompleteActivity.java](src/main/java/com/example/maps3djava/placeautocomplete/PlaceAutocompleteActivity.java) | |
| **Place Details** | 🚧 Skeleton | [PlaceDetailsActivity.java](src/main/java/com/example/maps3djava/placedetails/PlaceDetailsActivity.java) | |
| **Advanced Camera Animation** | 🚧 Skeleton | [AdvancedCameraAnimationActivity.java](src/main/java/com/example/maps3djava/advancedcameraanimation/AdvancedCameraAnimationActivity.java) | |
| **Data Visualization** | 🚧 Skeleton | [DataVisualizationActivity.java](src/main/java/com/example/maps3djava/datavisualization/DataVisualizationActivity.java) | |
| **Cloud Map Styling** | 🚧 Skeleton | [CloudStylingActivity.java](src/main/java/com/example/maps3djava/cloudstyling/CloudStylingActivity.java) | |
| **Roadmap Mode** | 🚧 Skeleton | [RoadmapModeActivity.java](src/main/java/com/example/maps3djava/roadmapmode/RoadmapModeActivity.java) | |
| **Field Of View** | 🚧 Skeleton | [FieldOfViewActivity.java](src/main/java/com/example/maps3djava/fieldofview/FieldOfViewActivity.java) | |

---
> [!NOTE]
> These samples are view-based and serve as a reference for Java developers.
> Status `🚧 Skeleton` means the activity exists and can be launched from the main list, but contains a TODO placeholder UI.
2 changes: 2 additions & 0 deletions Maps3DSamples/ApiDemos/java-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ dependencies {
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(project(":Maps3DSamples:ApiDemos:common"))
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(project(":visual-testing"))
androidTestImplementation(libs.androidx.uiautomator)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
androidTestImplementation(libs.google.truth)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading