From 01b5e930efda22cdb5e54776196a39de7106faee Mon Sep 17 00:00:00 2001 From: Ashik Abbas Date: Thu, 2 Jul 2026 09:42:07 +0530 Subject: [PATCH 1/4] migrate maps3D 0.2.0 to 0.2.2 Still OnMapReadyListener and OnMapSteadyListener are not invoked immediately if map is already ready/steady state. --- Maps3DSamples/ApiDemos/common/build.gradle.kts | 2 +- Maps3DSamples/ApiDemos/gradle/libs.versions.toml | 2 +- .../sampleactivity/SampleBaseActivity.kt | 4 ++-- .../basicmap/BasicComposeMapActivity.kt | 6 +++--- .../route/RouteSampleActivity.kt | 4 ++-- .../scenarios/CameraAttributesScreen.kt | 3 +-- .../advancedmaps3dsamples/scenarios/Scenario.kt | 12 ++++++------ .../scenarios/ScenarioMapper.kt | 11 +++++------ .../scenarios/ScenarioScreen.kt | 3 +-- .../advancedmaps3dsamples/scenarios/ThreeDMap.kt | 6 +++--- Maps3DSamples/advanced/gradle/libs.versions.toml | 2 +- .../java/com/example/placesuikit3d/MainActivity.kt | 3 ++- gradle/libs.versions.toml | 2 +- .../com/google/maps/android/compose3d/GoogleMap3D.kt | 4 ++-- snippets/gradle/libs.versions.toml | 2 +- .../snippets/java/snippets/MapInitSnippets.java | 3 ++- .../snippets/kotlin/snippets/MapInitSnippets.kt | 3 ++- 17 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Maps3DSamples/ApiDemos/common/build.gradle.kts b/Maps3DSamples/ApiDemos/common/build.gradle.kts index 58abe750..163eed90 100644 --- a/Maps3DSamples/ApiDemos/common/build.gradle.kts +++ b/Maps3DSamples/ApiDemos/common/build.gradle.kts @@ -70,6 +70,6 @@ dependencies { implementation(libs.androidx.material3) api(libs.play.services.base) // "com.google.android.gms:play-services-base:18.10.0" - api(libs.play.services.maps3d) // "com.google.android.gms:play-services-maps3d:0.2.0" + api(libs.play.services.maps3d) // "com.google.android.gms:play-services-maps3d:0.2.2" api(libs.maps.utils.ktx) } diff --git a/Maps3DSamples/ApiDemos/gradle/libs.versions.toml b/Maps3DSamples/ApiDemos/gradle/libs.versions.toml index e575c230..9d3dd5e9 100644 --- a/Maps3DSamples/ApiDemos/gradle/libs.versions.toml +++ b/Maps3DSamples/ApiDemos/gradle/libs.versions.toml @@ -17,7 +17,7 @@ lifecycleRuntimeKtx = "2.10.0" material = "1.13.0" playServicesBase = "18.10.0" -playServicesMaps3d = "0.2.0" +playServicesMaps3d = "0.2.2" secretsGradlePlugin = "2.0.1" truth = "1.4.5" uiautomator = "2.3.0" diff --git a/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/sampleactivity/SampleBaseActivity.kt b/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/sampleactivity/SampleBaseActivity.kt index bb98ea4f..564fe032 100644 --- a/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/sampleactivity/SampleBaseActivity.kt +++ b/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/sampleactivity/SampleBaseActivity.kt @@ -235,8 +235,8 @@ abstract class SampleBaseActivity : AppCompatActivity(), OnMap3DViewReadyCallbac Log.d(TAG, "onMap3DViewReady called") Log.d(TAG, "Setting initial camera: " + initialCamera.toCameraString()) // Wire up the standardized listener - googleMap3D.setOnMapReadyListener { - Log.w(TAG, "on map ready listener") + googleMap3D.setOnMapReadyListener { sceneReadiness-> + Log.w(TAG, "on map ready listener $sceneReadiness") googleMap3D.setOnMapReadyListener(null) onMapReady(googleMap3D) } diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt index 3a87888c..a192583d 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt @@ -18,7 +18,7 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import com.example.advancedmaps3dsamples.ui.theme.AdvancedMaps3DSamplesTheme import com.google.android.gms.maps3d.GoogleMap3D -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback @@ -51,8 +51,8 @@ class BasicComposeMapActivity : ComponentActivity() { // Composable enters the composition. Without `remember`, a new Map3DView would // be created on every recomposition, causing severe performance issues and losing state. val map3DView = remember { - // Map3DOptions allows us to set the initial camera position and orientation. - val options = Map3DOptions( + // Map3DInitConfig allows us to set the initial camera position and orientation. + val options = Map3DInitConfig.create( centerLat = 21.350, centerLng = -157.800, centerAlt = 0.0, diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt index e597011f..9a67a69b 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt @@ -94,7 +94,7 @@ import com.example.advancedmaps3dsamples.utils.toHeading import com.example.advancedmaps3dsamples.utils.toValidCamera import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps3d.GoogleMap3D -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback import com.google.android.gms.maps3d.model.AltitudeMode @@ -335,7 +335,7 @@ private fun Map3DViewport( ) { val context = LocalContext.current AndroidView(modifier = Modifier.fillMaxSize().testTag("map3d_view"), factory = { - val options = Map3DOptions( + val options = Map3DInitConfig.create( centerLat = 21.350, centerLng = -157.800, centerAlt = 0.0, diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/CameraAttributesScreen.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/CameraAttributesScreen.kt index 074c543e..f420cb76 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/CameraAttributesScreen.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/CameraAttributesScreen.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.example.advancedmaps3dsamples.utils.wrapIn -import com.google.android.gms.maps3d.GoogleMap3D private val headingSliderRange = -180f..180f private val tiltSliderRange = 0f..90f @@ -71,7 +70,7 @@ fun CameraControlDemoScreen( Column(modifier = Modifier.fillMaxSize()) { ThreeDMap( modifier = Modifier.fillMaxWidth().weight(1f), - options = scenario.mapsOptions, + mapsConfig = scenario.mapsConfig, viewModel = viewModel, ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/Scenario.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/Scenario.kt index 97fef5bb..f2390032 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/Scenario.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/Scenario.kt @@ -16,7 +16,7 @@ package com.example.advancedmaps3dsamples.scenarios import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.model.Camera import com.google.android.gms.maps3d.model.MarkerOptions import com.google.android.gms.maps3d.model.ModelOptions // Import ModelOptions @@ -28,7 +28,7 @@ import com.google.android.gms.maps3d.model.latLngAltitude data class Scenario( val name: String, val titleId: Int, - val mapsOptions: Map3DOptions, + val mapsConfig: Map3DInitConfig, val animationSteps: List = emptyList(), val markers: List = emptyList(), val models: List = emptyList(), // Add models property @@ -38,8 +38,8 @@ data class Scenario( @Composable fun getTitle() = stringResource(titleId) fun reset(viewModel: ScenariosViewModel) { - viewModel.setCamera(mapsOptions.toCamera()) // Set initial camera - viewModel.setMapMode(mapsOptions.mapMode) + viewModel.setCamera(mapsConfig.toCamera()) // Set initial camera + viewModel.setMapMode(mapsConfig.mapMode) viewModel.clearObjects() @@ -74,7 +74,7 @@ fun createScenario( return Scenario( name = name, titleId = titleId, - mapsOptions = initialState.toMaps3DOptions(), + mapsConfig = initialState.toMaps3DInitConfig(), animationSteps = animationString.toAnimation(), markers = markers.toMarkers(), models = models.toModels(), @@ -83,7 +83,7 @@ fun createScenario( ) } -fun Map3DOptions.toCamera(): Camera { +fun Map3DInitConfig.toCamera(): Camera { val options = this return camera { center = latLngAltitude { diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt index af54136a..99868ea4 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt @@ -22,7 +22,7 @@ import com.example.advancedmaps3dsamples.utils.toRoll import com.example.advancedmaps3dsamples.utils.toTilt import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps3d.model.PolygonOptions -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.model.AltitudeMode import com.google.android.gms.maps3d.model.Camera import com.google.android.gms.maps3d.model.CollisionBehavior @@ -189,15 +189,15 @@ fun String.toAnimation(): List { } } -fun String.toMaps3DOptions(): Map3DOptions { +fun String.toMaps3DInitConfig(): Map3DInitConfig { var camera: Camera? = null var mode: Int = Map3DMode.SATELLITE val optionsString = this.trim().trimEnd(';') if (optionsString.isBlank()) { - Log.w(TAG, "Empty initialState string provided for Map3DOptions") + Log.w(TAG, "Empty initialState string provided for Map3DInitConfig") // Return default options - return Map3DOptions(defaultUiDisabled = true) + return Map3DInitConfig.create() } optionsString.split(";").forEach { option -> @@ -227,8 +227,7 @@ fun String.toMaps3DOptions(): Map3DOptions { altitude = 10_000_000.0 } - return Map3DOptions( - defaultUiDisabled = true, + return Map3DInitConfig.create( centerLat = camera?.center?.latitude ?: defaultCameraPos.latitude, centerLng = camera?.center?.longitude ?: defaultCameraPos.longitude, centerAlt = camera?.center?.altitude ?: defaultCameraPos.altitude, diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioScreen.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioScreen.kt index cf67fc2f..12939082 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioScreen.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioScreen.kt @@ -16,7 +16,6 @@ package com.example.advancedmaps3dsamples.scenarios import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.google.android.gms.maps3d.GoogleMap3D @Composable fun ScenarioScreen( @@ -26,7 +25,7 @@ fun ScenarioScreen( ) { ThreeDMap( modifier = modifier, - options = scenario.mapsOptions, + mapsConfig = scenario.mapsConfig, viewModel = viewModel, ) } diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt index 224d4706..72a18ea0 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt @@ -21,13 +21,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.viewinterop.AndroidView import com.google.android.gms.maps3d.GoogleMap3D -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback @Composable internal fun ThreeDMap( - options: Map3DOptions, + mapsConfig: Map3DInitConfig, viewModel: ScenariosViewModel, modifier: Modifier = Modifier, ) { @@ -39,7 +39,7 @@ internal fun ThreeDMap( AndroidView( modifier = modifier.testTag("map3d_view"), factory = { context -> - val map3dView = Map3DView(context = context, options = options) + val map3dView = Map3DView(context = context, config = mapsConfig) map3dView.onCreate(null) map3dView.getMap3DViewAsync( diff --git a/Maps3DSamples/advanced/gradle/libs.versions.toml b/Maps3DSamples/advanced/gradle/libs.versions.toml index 33a5bb4d..0682da07 100644 --- a/Maps3DSamples/advanced/gradle/libs.versions.toml +++ b/Maps3DSamples/advanced/gradle/libs.versions.toml @@ -18,7 +18,7 @@ composeBom = "2026.01.01" hilt = "2.57.2" ksp = "2.2.20-2.0.2" -playServicesMaps3d = "0.2.0" +playServicesMaps3d = "0.2.2" playServicesBase = "18.10.0" secretsGradlePlugin = "2.0.1" truth = "1.4.5" diff --git a/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt b/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt index 5c231f5a..abd120b4 100644 --- a/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt +++ b/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt @@ -67,6 +67,7 @@ import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices import com.google.android.gms.maps3d.GoogleMap3D import com.google.android.gms.maps3d.OnMap3DViewReadyCallback +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.model.Camera import com.google.android.gms.maps3d.model.Map3DMode import com.google.android.gms.maps3d.model.camera @@ -196,7 +197,7 @@ class MainActivity : AppCompatActivity(), OnMap3DViewReadyCallback { val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current val map3DView = remember { - com.google.android.gms.maps3d.Map3DView(context).apply { + com.google.android.gms.maps3d.Map3DView(context, Map3DInitConfig.create()).apply { getMap3DViewAsync(this@MainActivity) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dc23fdd4..5759a442 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ lifecycleRuntimeKtx = "2.10.0" material = "1.13.0" playServicesBase = "18.10.0" -playServicesMaps3d = "0.2.0" +playServicesMaps3d = "0.2.2" places = "5.3.0" secretsGradlePlugin = "2.0.1" truth = "1.4.5" diff --git a/maps3d-compose/src/main/java/com/google/maps/android/compose3d/GoogleMap3D.kt b/maps3d-compose/src/main/java/com/google/maps/android/compose3d/GoogleMap3D.kt index 2cfe9c36..9f1f25f6 100644 --- a/maps3d-compose/src/main/java/com/google/maps/android/compose3d/GoogleMap3D.kt +++ b/maps3d-compose/src/main/java/com/google/maps/android/compose3d/GoogleMap3D.kt @@ -24,7 +24,7 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import com.google.android.gms.maps3d.GoogleMap3D -import com.google.android.gms.maps3d.Map3DOptions +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback import com.google.android.gms.maps3d.model.Camera @@ -69,7 +69,7 @@ fun GoogleMap3D( popovers: List = emptyList(), cameraRestriction: CameraRestriction? = null, @Map3DMode mapMode: Int = Map3DMode.SATELLITE, - options: Map3DOptions = Map3DOptions(), + options: Map3DInitConfig = Map3DInitConfig.create(), onMapReady: (GoogleMap3D) -> Unit = {}, onMapSteady: () -> Unit = {}, onMapClick: ((LatLngAltitude) -> Unit)? = null, diff --git a/snippets/gradle/libs.versions.toml b/snippets/gradle/libs.versions.toml index 0638374f..d761bc38 100644 --- a/snippets/gradle/libs.versions.toml +++ b/snippets/gradle/libs.versions.toml @@ -17,7 +17,7 @@ lifecycleRuntimeKtx = "2.10.0" material = "1.13.0" playServicesBase = "18.10.0" -playServicesMaps3d = "0.2.0" +playServicesMaps3d = "0.2.2" secretsGradlePlugin = "2.0.1" truth = "1.4.5" uiautomator = "2.3.0" diff --git a/snippets/java-app/src/main/java/com/example/snippets/java/snippets/MapInitSnippets.java b/snippets/java-app/src/main/java/com/example/snippets/java/snippets/MapInitSnippets.java index 475ee942..a06d47ed 100644 --- a/snippets/java-app/src/main/java/com/example/snippets/java/snippets/MapInitSnippets.java +++ b/snippets/java-app/src/main/java/com/example/snippets/java/snippets/MapInitSnippets.java @@ -25,6 +25,7 @@ import com.example.snippets.java.annotations.SnippetGroup; import com.example.snippets.java.annotations.SnippetItem; import com.google.android.gms.maps3d.GoogleMap3D; +import com.google.android.gms.maps3d.Map3DInitConfig; import com.google.android.gms.maps3d.Map3DView; import com.google.android.gms.maps3d.OnMap3DViewReadyCallback; import com.google.android.gms.maps3d.OnMapReadyListener; @@ -43,7 +44,7 @@ public class MapInitSnippets { @SuppressWarnings("unused") public void basicMap3D(Context context) { // [START maps_android_3d_init_basic_java] - Map3DView map3DView = new Map3DView(context); + Map3DView map3DView = new Map3DView(context, Map3DInitConfig.create()); // Get the map asynchronously map3DView.getMap3DViewAsync( diff --git a/snippets/kotlin-app/src/main/java/com/example/snippets/kotlin/snippets/MapInitSnippets.kt b/snippets/kotlin-app/src/main/java/com/example/snippets/kotlin/snippets/MapInitSnippets.kt index d9625489..b9c3a6dc 100644 --- a/snippets/kotlin-app/src/main/java/com/example/snippets/kotlin/snippets/MapInitSnippets.kt +++ b/snippets/kotlin-app/src/main/java/com/example/snippets/kotlin/snippets/MapInitSnippets.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.viewinterop.AndroidView import com.example.snippets.kotlin.annotations.SnippetGroup import com.example.snippets.kotlin.annotations.SnippetItem import com.google.android.gms.maps3d.GoogleMap3D +import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback import com.google.android.gms.maps3d.model.camera @@ -55,7 +56,7 @@ class MapInitSnippets { AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> - Map3DView(context).apply { + Map3DView(context, Map3DInitConfig.create()).apply { getMap3DViewAsync(object : OnMap3DViewReadyCallback { override fun onMap3DViewReady(googleMap3D: GoogleMap3D) { val camera = camera { From 91d57ecedd021e6be3c1625a0f4954fc670afe0e Mon Sep 17 00:00:00 2001 From: Dale Hawkins <107309+dkhawk@users.noreply.github.com> Date: Fri, 7 Aug 2026 16:51:45 -0600 Subject: [PATCH 2/4] build(deps): target Android 37, upgrade AGP to 9.2.1, update dependencies, and add migration guide - Target Android API 37 (compileSdk = 37, targetSdk = 36) - Upgrade Android Gradle Plugin to 9.2.1 across all subprojects - Update dependencies to latest versions (core-ktx 1.19.0, lifecycle-runtime-ktx 2.11.0, material 1.14.0, maps-utils-ktx 6.3.0, ktor 3.5.2, spotless 8.9.0) - Add MIGRATION_GUIDE.md and link in README.md - Set Gradle daemon heap to 4096m in gradle.properties TAG=agy CONV=28fd0e13-f824-4115-9a06-5c361f22ee37 --- .gitignore | 4 +- MIGRATION_GUIDE.md | 94 +++++++++++++++++++ .../ApiDemos/gradle/libs.versions.toml | 16 ++-- .../advanced/gradle/libs.versions.toml | 24 ++--- README.md | 4 + gradle.properties | 2 +- gradle/libs.versions.toml | 14 +-- snippets/gradle/libs.versions.toml | 16 ++-- 8 files changed, 135 insertions(+), 39 deletions(-) create mode 100644 MIGRATION_GUIDE.md diff --git a/.gitignore b/.gitignore index 70ff3fc7..c32cfa86 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,4 @@ google-services.json # VS Code .vscode/ snippets/docs/ - - - +.kotlin/ diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 00000000..08f39fb6 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,94 @@ +# Android Maps 3D SDK Migration Guide + +This guide assists developers in migrating their codebases to newer versions of the Android Maps 3D SDK. + +> [!TIP] +> **AI Migration Prompt**: If you are using an AI coding assistant (such as Gemini, Copilot, or Cursor), you can use this document as a prompt to automatically migrate your codebase. +> +> **Instructions for AI**: +> 1. Read the section corresponding to the version upgrade. +> 2. Analyze the "Before" and "After" patterns. +> 3. Scan the codebase for the "Before" patterns and apply the transformations to match the "After" patterns. +> 4. Ensure all imports are updated accordingly. + +--- + +## Migrating from 0.2.0 to 0.2.2 + +This release introduces breaking changes to the initialization configuration and view construction. + +### 1. Dependency Update +Update the SDK dependency version in your `build.gradle` or `gradle/libs.versions.toml`. + +* **Action**: Update `playServicesMaps3d` version to `0.2.2`. + +### 2. Replace `Map3DOptions` with `Map3DInitConfig` + +The `Map3DOptions` class has been removed. Use `Map3DInitConfig` instead. +* **Rule**: `Map3DInitConfig` cannot be created via a constructor. Use the static `Map3DInitConfig.create()` factory method and chain `.copy(...)` to modify properties. + +#### Code Transformation: + +**Kotlin**: +```diff +-val options = Map3DOptions( +- centerLat = 21.350, +- centerLng = -157.800, +- centerAlt = 0.0, +- tilt = 60.0, +- range = 25000.0 +-) ++val config = Map3DInitConfig.create().copy( ++ centerLat = 21.350, ++ centerLng = -157.800, ++ centerAlt = 0.0, ++ tilt = 60.0, ++ range = 25000.0 ++) +``` + +**Java**: +```diff +-Map3DOptions options = new Map3DOptions(); +-options.setCenterLat(21.350); +-options.setCenterLng(-157.800); ++Map3DInitConfig config = Map3DInitConfig.create( ++ 21.350, // centerLat ++ -157.800, // centerLng ++ 0.0, // centerAlt ++ 0.0, // heading ++ 60.0, // tilt ++ 0.0, // roll ++ 25000.0 // range ++); +``` + +### 3. Update `Map3DView` Construction + +The default `Map3DView(Context)` constructor has been removed. You must now pass a `Map3DInitConfig` or a `mapMode`. + +#### Code Transformation: + +**Kotlin**: +```diff +-val view = Map3DView(context) ++val view = Map3DView(context, Map3DInitConfig.create()) +``` + +**Java**: +```diff +-Map3DView view = new Map3DView(context); ++Map3DView view = new Map3DView(context, Map3DInitConfig.create()); +``` + +### 4. Update Kotlin Named Parameters +If you construct `Map3DView` using named parameters, change `options` to `config`. + +#### Code Transformation: +```diff +-val view = Map3DView(context = context, options = myConfig) ++val view = Map3DView(context = context, config = myConfig) +``` + +### 5. Remove `FacingMode` +The `FacingMode` enum has been removed. Remove all references to `FacingMode.SCREEN` or `FacingMode.BILLBOARD`. diff --git a/Maps3DSamples/ApiDemos/gradle/libs.versions.toml b/Maps3DSamples/ApiDemos/gradle/libs.versions.toml index 9d3dd5e9..2fdcd9c0 100644 --- a/Maps3DSamples/ApiDemos/gradle/libs.versions.toml +++ b/Maps3DSamples/ApiDemos/gradle/libs.versions.toml @@ -3,24 +3,24 @@ compileSdk = "37" minSdk = "26" targetSdk = "36" -activityCompose = "1.12.4" -agp = "8.13.2" +activityCompose = "1.13.0" +agp = "9.2.1" appcompat = "1.7.1" -composeBom = "2026.02.01" -coreKtx = "1.17.0" +composeBom = "2026.06.01" +coreKtx = "1.19.0" desugar_jdk_libs = "2.1.5" espressoCore = "3.7.0" junit = "4.13.2" junitVersion = "1.3.0" -kotlin = "2.2.0" -lifecycleRuntimeKtx = "2.10.0" -material = "1.13.0" +kotlin = "2.3.20" +lifecycleRuntimeKtx = "2.11.0" +material = "1.14.0" playServicesBase = "18.10.0" playServicesMaps3d = "0.2.2" secretsGradlePlugin = "2.0.1" truth = "1.4.5" -uiautomator = "2.3.0" +uiautomator = "2.4.0" robolectric = "4.16.1" androidxTestCore = "1.7.0" diff --git a/Maps3DSamples/advanced/gradle/libs.versions.toml b/Maps3DSamples/advanced/gradle/libs.versions.toml index 0682da07..e0eb7b29 100644 --- a/Maps3DSamples/advanced/gradle/libs.versions.toml +++ b/Maps3DSamples/advanced/gradle/libs.versions.toml @@ -3,26 +3,26 @@ compileSdk = "37" minSdk = "26" targetSdk = "36" -agp = "8.13.2" -kotlin = "2.2.20" -kotlinxDatetime = "0.7.1" -kotlinxSerialization = "1.7.3" -ktor = "3.0.3" -coreKtx = "1.17.0" +agp = "9.2.1" +kotlin = "2.3.20" +kotlinxDatetime = "0.8.0" +kotlinxSerialization = "1.11.0" +ktor = "3.5.2" +coreKtx = "1.19.0" junit = "4.13.2" junitVersion = "1.3.0" espressoCore = "3.7.0" -lifecycleRuntimeKtx = "2.10.0" -activityCompose = "1.12.3" -composeBom = "2026.01.01" +lifecycleRuntimeKtx = "2.11.0" +activityCompose = "1.13.0" +composeBom = "2026.06.01" -hilt = "2.57.2" -ksp = "2.2.20-2.0.2" +hilt = "2.60.1" +ksp = "2.3.6" playServicesMaps3d = "0.2.2" playServicesBase = "18.10.0" secretsGradlePlugin = "2.0.1" truth = "1.4.5" -mapsUtilsKtx = "6.0.0" +mapsUtilsKtx = "6.3.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } diff --git a/README.md b/README.md index 849eaede..d2a6ee0d 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,10 @@ As a reference, you can view the [Gemini CLI documentation](https://geminicli.co Alternatively, use the `gradlew build` command within a sample's directory to build the project directly or download an APK under [releases](https://github.com/googlemaps/android-maps3d-samples/releases) (if available for the specific sample). +## Migration + +If you are upgrading from an older version of the SDK, please refer to the [Migration Guide](MIGRATION_GUIDE.md) for details on breaking changes and how to update your codebase. + ## Contributing Contributions are welcome and encouraged! If you'd like to contribute, send us a [pull request] and refer to our [code of conduct] and [contributing guide]. diff --git a/gradle.properties b/gradle.properties index 4540b754..b1b8ecc9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. For more details, visit # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5759a442..a4e94c85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,17 +8,17 @@ json = "20260522" robolectric = "4.16.1" activityCompose = "1.13.0" -agp = "9.1.0" +agp = "9.2.1" appcompat = "1.7.1" composeBom = "2026.06.01" -coreKtx = "1.18.0" +coreKtx = "1.19.0" desugar_jdk_libs = "2.1.5" espressoCore = "3.7.0" junit = "4.13.2" junitVersion = "1.3.0" kotlin = "2.3.20" -lifecycleRuntimeKtx = "2.10.0" -material = "1.13.0" +lifecycleRuntimeKtx = "2.11.0" +material = "1.14.0" playServicesBase = "18.10.0" playServicesMaps3d = "0.2.2" @@ -26,14 +26,14 @@ places = "5.3.0" secretsGradlePlugin = "2.0.1" truth = "1.4.5" uiautomator = "2.4.0" -spotless = "8.4.0" +spotless = "8.9.0" kotlinxDatetime = "0.8.0" kotlinxSerialization = "1.11.0" -ktor = "3.5.1" +ktor = "3.5.2" hilt = "2.60.1" ksp = "2.3.6" -mapsUtilsKtx = "6.1.0" +mapsUtilsKtx = "6.3.0" androidx-core-ktx = "1.8.9" [libraries] diff --git a/snippets/gradle/libs.versions.toml b/snippets/gradle/libs.versions.toml index d761bc38..00e2354f 100644 --- a/snippets/gradle/libs.versions.toml +++ b/snippets/gradle/libs.versions.toml @@ -3,24 +3,24 @@ compileSdk = "37" minSdk = "26" targetSdk = "36" -activityCompose = "1.12.4" -agp = "8.13.2" +activityCompose = "1.13.0" +agp = "9.2.1" appcompat = "1.7.1" -composeBom = "2026.02.01" -coreKtx = "1.17.0" +composeBom = "2026.06.01" +coreKtx = "1.19.0" desugar_jdk_libs = "2.1.5" espressoCore = "3.7.0" junit = "4.13.2" junitVersion = "1.3.0" -kotlin = "2.3.0" -lifecycleRuntimeKtx = "2.10.0" -material = "1.13.0" +kotlin = "2.3.20" +lifecycleRuntimeKtx = "2.11.0" +material = "1.14.0" playServicesBase = "18.10.0" playServicesMaps3d = "0.2.2" secretsGradlePlugin = "2.0.1" truth = "1.4.5" -uiautomator = "2.3.0" +uiautomator = "2.4.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } From ddb778a5aaacdaaa39218a41d9ab00b1eddf85bf Mon Sep 17 00:00:00 2001 From: Ashik Abbas Date: Mon, 10 Aug 2026 15:16:19 +0530 Subject: [PATCH 3/4] Fixed Map3DInitConfig.create crash and setMap3DClickListener crash --- .../MapInteractionsActivity.kt | 18 +++++++------ .../basicmap/BasicComposeMapActivity.kt | 21 +++++++++++++--- .../route/RouteSampleActivity.kt | 25 +++++++++++++++---- .../scenarios/ScenarioMapper.kt | 9 +++++-- 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/mapinteractions/MapInteractionsActivity.kt b/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/mapinteractions/MapInteractionsActivity.kt index 4c687741..8a42f1f9 100644 --- a/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/mapinteractions/MapInteractionsActivity.kt +++ b/Maps3DSamples/ApiDemos/kotlin-app/src/main/java/com/example/maps3dkotlin/mapinteractions/MapInteractionsActivity.kt @@ -21,13 +21,13 @@ import android.widget.TextView import android.widget.Toast import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope +import com.example.maps3dcommon.R import com.example.maps3dkotlin.sampleactivity.SampleBaseActivity import com.google.android.gms.maps3d.GoogleMap3D import com.google.android.gms.maps3d.model.Map3DMode import com.google.android.gms.maps3d.model.camera import com.google.android.gms.maps3d.model.latLngAltitude import kotlinx.coroutines.launch -import com.example.maps3dcommon.R class MapInteractionsActivity : SampleBaseActivity() { override val TAG = this::class.java.simpleName @@ -63,14 +63,16 @@ class MapInteractionsActivity : SampleBaseActivity() { // Listeners for map clicks. We use lifecycleScope to ensure coroutines are cancelled when the activity is destroyed. lifecycleScope.launch { googleMap3D.setMap3DClickListener { location, placeId -> - val message = if (placeId != null) { - "Clicked Place ID: $placeId" - } else { - "Clicked Location: ${location.latitude}, ${location.longitude}" + runOnUiThread { + val message = if (placeId != null) { + "Clicked Place ID: $placeId" + } else { + "Clicked Location: ${location.latitude}, ${location.longitude}" + } + clickedInfoText.text = message + clickedInfoText.contentDescription = message + showToast(message) } - clickedInfoText.text = message - clickedInfoText.contentDescription = message - showToast(message) } } } diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt index a192583d..1f686513 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/basicmap/BasicComposeMapActivity.kt @@ -21,6 +21,8 @@ import com.google.android.gms.maps3d.GoogleMap3D import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback +import com.google.android.gms.maps3d.model.Map3DMode +import java.util.Locale /** * A minimal reference example demonstrating how to integrate the Google Maps 3D SDK @@ -55,9 +57,22 @@ class BasicComposeMapActivity : ComponentActivity() { val options = Map3DInitConfig.create( centerLat = 21.350, centerLng = -157.800, - centerAlt = 0.0, - tilt = 60.0, - range = 25000.0 + centerAlt = 250.0, + heading = 45.0, + tilt = 65.0, + roll = 0.0, + range = 800.0, + minAltitude = 0.0, + maxAltitude = 1000000.0, + minHeading = 0.0, + maxHeading = 360.0, + minTilt = 0.0, + maxTilt = 90.0, + bounds = null, + mapMode = Map3DMode.HYBRID, + mapId = null, + language = Locale.getDefault().language, + region = Locale.getDefault().country ) Map3DView(context, options).apply { // Map3DView loads its resources asynchronously. We must provide a callback diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt index 9a67a69b..b0c1d27c 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/route/RouteSampleActivity.kt @@ -80,14 +80,16 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.platform.testTag import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.content.edit import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.advancedmaps3dsamples.BuildConfig import com.example.advancedmaps3dsamples.R import com.example.advancedmaps3dsamples.ui.theme.AdvancedMaps3DSamplesTheme +import com.example.advancedmaps3dsamples.utils.GeoMathUtils import com.example.advancedmaps3dsamples.utils.calculateHeading import com.example.advancedmaps3dsamples.utils.haversineDistance import com.example.advancedmaps3dsamples.utils.toHeading @@ -99,6 +101,7 @@ import com.google.android.gms.maps3d.Map3DView import com.google.android.gms.maps3d.OnMap3DViewReadyCallback import com.google.android.gms.maps3d.model.AltitudeMode import com.google.android.gms.maps3d.model.ImageView +import com.google.android.gms.maps3d.model.Map3DMode import com.google.android.gms.maps3d.model.Polyline import com.google.android.gms.maps3d.model.camera import com.google.android.gms.maps3d.model.latLngAltitude @@ -106,13 +109,12 @@ import com.google.android.gms.maps3d.model.markerOptions import com.google.android.gms.maps3d.model.modelOptions import com.google.android.gms.maps3d.model.orientation import com.google.android.gms.maps3d.model.polylineOptions -import com.example.advancedmaps3dsamples.utils.GeoMathUtils import com.google.android.gms.maps3d.model.vector3D import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.delay -import androidx.core.content.edit +import java.util.Locale import kotlin.math.abs import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.delay sealed interface RouteTracker { val name: String @@ -340,7 +342,20 @@ private fun Map3DViewport( centerLng = -157.800, centerAlt = 0.0, tilt = 60.0, - range = 25000.0 + range = 25000.0, + heading = 45.0, + roll = 0.0, + minAltitude = 0.0, + maxAltitude = 1000000.0, + minHeading = 0.0, + maxHeading = 360.0, + minTilt = 0.0, + maxTilt = 90.0, + bounds = null, + mapMode = Map3DMode.HYBRID, + mapId = null, + language = Locale.getDefault().language, + region = Locale.getDefault().country ) val view = Map3DView(context, options) view.onCreate(null) diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt index 99868ea4..c1866dc5 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt @@ -16,12 +16,12 @@ package com.example.advancedmaps3dsamples.scenarios import android.graphics.Color import android.util.Log +import androidx.core.graphics.toColorInt import com.example.advancedmaps3dsamples.utils.toHeading import com.example.advancedmaps3dsamples.utils.toRange import com.example.advancedmaps3dsamples.utils.toRoll import com.example.advancedmaps3dsamples.utils.toTilt import com.google.android.gms.maps.model.LatLng -import com.google.android.gms.maps3d.model.PolygonOptions import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.model.AltitudeMode import com.google.android.gms.maps3d.model.Camera @@ -33,6 +33,7 @@ import com.google.android.gms.maps3d.model.LatLngAltitude import com.google.android.gms.maps3d.model.Map3DMode import com.google.android.gms.maps3d.model.MarkerOptions import com.google.android.gms.maps3d.model.ModelOptions +import com.google.android.gms.maps3d.model.PolygonOptions import com.google.android.gms.maps3d.model.PolylineOptions import com.google.android.gms.maps3d.model.camera import com.google.android.gms.maps3d.model.flyAroundOptions @@ -45,8 +46,8 @@ import com.google.android.gms.maps3d.model.polygonOptions import com.google.android.gms.maps3d.model.polylineOptions import com.google.android.gms.maps3d.model.vector3D import com.google.maps.android.ktx.utils.toLatLngList +import java.util.Locale import java.util.UUID -import androidx.core.graphics.toColorInt private const val TAG = "ScenarioMapper" @@ -242,6 +243,10 @@ fun String.toMaps3DInitConfig(): Map3DInitConfig { bounds = null, mapMode = mode, mapId = null, + minAltitude = 0.0, + maxAltitude = 1000000.0, + language = Locale.getDefault().language, + region = Locale.getDefault().country ) } From b09426a0134244d87c9de84f88c109ca0ae2eea0 Mon Sep 17 00:00:00 2001 From: Dale Hawkins <107309+dkhawk@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:19:21 -0600 Subject: [PATCH 4/4] Fix Map3DView lifecycle forwarding and explicit init config in samples --- .../scenarios/ScenarioMapper.kt | 34 ++++++------ .../scenarios/ThreeDMap.kt | 52 +++++++++++++------ .../com/example/placesuikit3d/MainActivity.kt | 26 +++++++++- 3 files changed, 76 insertions(+), 36 deletions(-) diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt index c1866dc5..03892003 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ScenarioMapper.kt @@ -195,29 +195,25 @@ fun String.toMaps3DInitConfig(): Map3DInitConfig { var mode: Int = Map3DMode.SATELLITE val optionsString = this.trim().trimEnd(';') - if (optionsString.isBlank()) { - Log.w(TAG, "Empty initialState string provided for Map3DInitConfig") - // Return default options - return Map3DInitConfig.create() - } + if (optionsString.isNotBlank()) { + optionsString.split(";").forEach { option -> + val trimmedOption = option.trim() + if (trimmedOption.contains('=')) { + val (label, value) = trimmedOption.split("=", limit = 2) + when (label.trim().lowercase()) { + "mode" -> { + mode = value.trim().toMap3DMode() + } - optionsString.split(";").forEach { option -> - val trimmedOption = option.trim() - if (trimmedOption.contains('=')) { - val (label, value) = trimmedOption.split("=", limit = 2) - when (label.trim().lowercase()) { - "mode" -> { - mode = value.trim().toMap3DMode() - } + "camera" -> { + camera = value.trim().toCamera() + } - "camera" -> { - camera = value.trim().toCamera() + else -> Log.w(TAG, "Unsupported Map3DOption key: $label") } - - else -> Log.w(TAG, "Unsupported Map3DOption key: $label") + } else { + Log.w(TAG, "Ignoring invalid Map3DOption format: $option") } - } else { - Log.w(TAG, "Ignoring invalid Map3DOption format: $option") } } diff --git a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt index 72a18ea0..8bead431 100644 --- a/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt +++ b/Maps3DSamples/advanced/app/src/main/java/com/example/advancedmaps3dsamples/scenarios/ThreeDMap.kt @@ -15,11 +15,17 @@ package com.example.advancedmaps3dsamples.scenarios import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.compose.LocalLifecycleOwner import com.google.android.gms.maps3d.GoogleMap3D import com.google.android.gms.maps3d.Map3DInitConfig import com.google.android.gms.maps3d.Map3DView @@ -31,23 +37,22 @@ internal fun ThreeDMap( viewModel: ScenariosViewModel, modifier: Modifier = Modifier, ) { + val context = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current + // Use rememberUpdatedState to avoid capturing stale callbacks if they change val currentOnMapSteadyChange by rememberUpdatedState { isSteady: Boolean -> viewModel.onMapSteadyChange(isSteady) } - AndroidView( - modifier = modifier.testTag("map3d_view"), - factory = { context -> - val map3dView = Map3DView(context = context, config = mapsConfig) - map3dView.onCreate(null) - - map3dView.getMap3DViewAsync( + val map3dView = remember(mapsConfig) { + Map3DView(context = context, config = mapsConfig).apply { + getMap3DViewAsync( object : OnMap3DViewReadyCallback { override fun onMap3DViewReady(googleMap3D: GoogleMap3D) { viewModel.setGoogleMap3D(googleMap3D) googleMap3D.setOnMapSteadyListener { isSceneSteady -> - currentOnMapSteadyChange(isSceneSteady) + currentOnMapSteadyChange(isSceneSteady) } } @@ -56,14 +61,31 @@ internal fun ThreeDMap( } } ) - - map3dView - }, - update = { _ -> - // No-op, updates are handled via viewModel and imperative calls on the stored instance - }, + } + } + + DisposableEffect(lifecycleOwner, map3dView) { + val observer = LifecycleEventObserver { _, event -> + when (event) { + Lifecycle.Event.ON_CREATE -> map3dView.onCreate(null) + Lifecycle.Event.ON_RESUME -> map3dView.onResume() + Lifecycle.Event.ON_PAUSE -> map3dView.onPause() + Lifecycle.Event.ON_DESTROY -> map3dView.onDestroy() + else -> {} + } + } + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + viewModel.releaseGoogleMap3D() + } + } + + AndroidView( + modifier = modifier.testTag("map3d_view"), + factory = { map3dView }, + update = { _ -> }, onRelease = { _ -> - // Clean up resources if needed viewModel.releaseGoogleMap3D() }, onReset = { _ -> }, diff --git a/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt b/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt index abd120b4..e97fb3d0 100644 --- a/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt +++ b/PlacesUIKit3D/src/main/java/com/example/placesuikit3d/MainActivity.kt @@ -197,7 +197,27 @@ class MainActivity : AppCompatActivity(), OnMap3DViewReadyCallback { val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current val map3DView = remember { - com.google.android.gms.maps3d.Map3DView(context, Map3DInitConfig.create()).apply { + val config = Map3DInitConfig.create( + centerLat = 39.982129291022446, + centerLng = -105.30156359691158, + centerAlt = 2483.51, + heading = 26.0, + tilt = 67.0, + roll = 0.0, + range = 4000.0, + minAltitude = 0.0, + maxAltitude = 1000000.0, + minHeading = 0.0, + maxHeading = 360.0, + minTilt = 0.0, + maxTilt = 90.0, + bounds = null, + mapMode = Map3DMode.HYBRID, + mapId = null, + language = java.util.Locale.getDefault().language, + region = java.util.Locale.getDefault().country + ) + com.google.android.gms.maps3d.Map3DView(context, config).apply { getMap3DViewAsync(this@MainActivity) } } @@ -359,7 +379,9 @@ class MainActivity : AppCompatActivity(), OnMap3DViewReadyCallback { googleMap3D.setMap3DClickListener { _, placeId -> Log.e(TAG, "Map clicked: placeId=$placeId") if (!placeId.isNullOrEmpty()) { - viewModel.setSelectedPlaceId(placeId) + runOnUiThread { + viewModel.setSelectedPlaceId(placeId) + } } }