diff --git a/ApiDemos/project/common-ui/src/main/res/layout/camera_clamping_demo.xml b/ApiDemos/project/common-ui/src/main/res/layout/camera_clamping_demo.xml index cb7cdd4c2..e790ff236 100644 --- a/ApiDemos/project/common-ui/src/main/res/layout/camera_clamping_demo.xml +++ b/ApiDemos/project/common-ui/src/main/res/layout/camera_clamping_demo.xml @@ -1,5 +1,5 @@ - + Maps SDK for Android Demos (Java) Maps SDK for Android Demos (Java) Maps SDK for Android Demos (Kotlin) @@ -32,12 +32,18 @@ Demonstrates how to use Camera Clamping. Camera Clamping Demo - Clamp to Adelaide - Clamp to Pacific - Reset LatLng Bounds + Adelaide + Pacific + Reset + Bounds: None + Bounds: Adelaide + Bounds: Pacific + Position: (%1$.6f, %2$.6f)\nzoom=%3$.1f, tilt=%4$.1f\u00b0, bearing=%5$.1f\u00b0 MinZoom++ - MaxZoom-- - Reset Zoom Bounds + MaxZoom-- + Reset Zoom + Zoom Limits: %1$.1f – %2$.1f + Zoom Limits: 2.0 – 21.0 Clear Clickable diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraClampingDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraClampingDemoActivity.java index ec2214601..44f13aff5 100644 --- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraClampingDemoActivity.java +++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/CameraClampingDemoActivity.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. @@ -31,13 +31,13 @@ * This shows how to constrain the camera to specific boundaries and zoom levels. */ public class CameraClampingDemoActivity extends SamplesBaseActivity - implements OnMapReadyCallback, OnCameraIdleListener { + implements OnMapReadyCallback, OnCameraIdleListener, GoogleMap.OnCameraMoveListener { private static final String TAG = CameraClampingDemoActivity.class.getSimpleName(); private static final float ZOOM_DELTA = 2.0f; private static final float DEFAULT_MIN_ZOOM = 2.0f; - private static final float DEFAULT_MAX_ZOOM = 22.0f; + private static final float DEFAULT_MAX_ZOOM = 21.0f; static final LatLngBounds ADELAIDE_BOUNDS = new LatLngBounds( new LatLng(-35.0, 138.58), new LatLng(-34.9, 138.61)); @@ -71,18 +71,27 @@ protected void onCreate(Bundle savedInstanceState) { mMap = null; resetMinMaxZoom(); + updateZoomLabel(mMinZoom, mMaxZoom); + + binding.zoomRangeSlider.addOnChangeListener((slider, value, fromUser) -> { + java.util.List values = slider.getValues(); + mMinZoom = values.get(0); + mMaxZoom = values.get(1); + updateZoomLabel(mMinZoom, mMaxZoom); + if (fromUser && mMap != null) { + mMap.setMinZoomPreference(mMinZoom); + mMap.setMaxZoomPreference(mMaxZoom); + } + }); binding.clampLatlngAdelaide.setOnClickListener(v -> onClampToAdelaide()); binding.clampLatlngPacific.setOnClickListener(v -> onClampToPacific()); binding.clampLatlngReset.setOnClickListener(v -> onLatLngClampReset()); - binding.clampMinZoom.setOnClickListener(v -> onSetMinZoomClamp()); - binding.clampMaxZoom.setOnClickListener(v -> onSetMaxZoomClamp()); binding.clampZoomReset.setOnClickListener(v -> onMinMaxZoomClampReset()); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map); mapFragment.getMapAsync(this); - applyInsets(binding.mapContainer); } @Override @@ -93,12 +102,36 @@ protected void onResume() { @Override public void onMapReady(GoogleMap map) { mMap = map; + map.setOnCameraMoveListener(this); map.setOnCameraIdleListener(this); + updateCameraPosition(); + } + + @Override + public void onCameraMove() { + updateCameraPosition(); } @Override public void onCameraIdle() { - binding.cameraText.setText(mMap.getCameraPosition().toString()); + updateCameraPosition(); + } + + private void updateCameraPosition() { + if (mMap == null) return; + CameraPosition pos = mMap.getCameraPosition(); + binding.cameraText.setText(getString( + com.example.common_ui.R.string.camera_position_format, + pos.target.latitude, + pos.target.longitude, + pos.zoom, + pos.tilt, + pos.bearing + )); + } + + private void updateZoomLabel(float min, float max) { + binding.zoomLabel.setText(getString(com.example.common_ui.R.string.zoom_bounds_label, min, max)); } /** @@ -126,53 +159,40 @@ private void onClampToAdelaide() { if (!checkReady()) { return; } + binding.latlngClampToggleGroup.check(com.example.common_ui.R.id.clamp_latlng_adelaide); mMap.setLatLngBoundsForCameraTarget(ADELAIDE_BOUNDS); mMap.animateCamera(CameraUpdateFactory.newCameraPosition(ADELAIDE_CAMERA)); + binding.clampStatusText.setText(getString(com.example.common_ui.R.string.latlng_clamp_status_adelaide)); } private void onClampToPacific() { if (!checkReady()) { return; } + binding.latlngClampToggleGroup.check(com.example.common_ui.R.id.clamp_latlng_pacific); mMap.setLatLngBoundsForCameraTarget(PACIFIC); mMap.animateCamera(CameraUpdateFactory.newCameraPosition(PACIFIC_CAMERA)); + binding.clampStatusText.setText(getString(com.example.common_ui.R.string.latlng_clamp_status_pacific)); } private void onLatLngClampReset() { if (!checkReady()) { return; } + binding.latlngClampToggleGroup.clearChecked(); // Setting bounds to null removes any previously set bounds. mMap.setLatLngBoundsForCameraTarget(null); + binding.clampStatusText.setText(getString(com.example.common_ui.R.string.latlng_clamp_status_none)); toast("LatLngBounds clamp reset."); } - private void onSetMinZoomClamp() { - if (!checkReady()) { - return; - } - mMinZoom += ZOOM_DELTA; - // Constrains the minimum zoom level. - mMap.setMinZoomPreference(mMinZoom); - toast("Min zoom preference set to: " + mMinZoom); - } - - private void onSetMaxZoomClamp() { - if (!checkReady()) { - return; - } - mMaxZoom -= ZOOM_DELTA; - // Constrains the maximum zoom level. - mMap.setMaxZoomPreference(mMaxZoom); - toast("Max zoom preference set to: " + mMaxZoom); - } - private void onMinMaxZoomClampReset() { - if (!checkReady()) { - return; - } resetMinMaxZoom(); - mMap.resetMinMaxZoomPreference(); + binding.zoomRangeSlider.setValues(DEFAULT_MIN_ZOOM, DEFAULT_MAX_ZOOM); + updateZoomLabel(DEFAULT_MIN_ZOOM, DEFAULT_MAX_ZOOM); + if (mMap != null) { + mMap.resetMinMaxZoomPreference(); + } toast("Min/Max zoom preferences reset."); } } \ No newline at end of file diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java index 6729049eb..bbabb704f 100755 --- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.java +++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/VisibleRegionDemoActivity.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. @@ -16,6 +16,7 @@ import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.SystemClock; import android.view.View; import android.view.animation.Interpolator; @@ -89,7 +90,8 @@ public void onMapReady(GoogleMap map) { // Add a marker to the Opera House. mMap.addMarker(new MarkerOptions().position(SOH).title("Sydney Opera House")); // Add a camera idle listener. - mMap.setOnCameraIdleListener(() -> binding.messageText.setText("CameraChangeListener: " + mMap.getCameraPosition())); + mMap.setOnCameraIdleListener(() -> binding.messageText.setText( + getString(com.example.common_ui.R.string.camera_change_message, mMap.getCameraPosition()))); } /** @@ -147,7 +149,7 @@ public void setMorePadding(View view) { public void animatePadding( final int toLeft, final int toTop, final int toRight, final int toBottom) { - final Handler handler = new Handler(); + final Handler handler = new Handler(Looper.getMainLooper()); final long start = SystemClock.uptimeMillis(); final long duration = 1000; diff --git a/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/VisibleRegionDemoActivity.java b/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/VisibleRegionDemoActivity.java index 41ede6037..3e94125be 100755 --- a/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/VisibleRegionDemoActivity.java +++ b/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/VisibleRegionDemoActivity.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. @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.SystemClock; import androidx.appcompat.app.AppCompatActivity; import android.view.View; @@ -86,7 +87,8 @@ public void onMapReady(GoogleMap map) { mMap.setOnCameraIdleListener(new OnCameraIdleListener() { @Override public void onCameraIdle() { - mMessageView.setText("CameraChangeListener: " + mMap.getCameraPosition()); + mMessageView.setText(getString( + com.example.common_ui.R.string.camera_change_message, mMap.getCameraPosition())); } }); } @@ -146,7 +148,7 @@ public void setMorePadding(View view) { public void animatePadding( final int toLeft, final int toTop, final int toRight, final int toBottom) { - final Handler handler = new Handler(); + final Handler handler = new Handler(Looper.getMainLooper()); final long start = SystemClock.uptimeMillis(); final long duration = 1000; diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CameraClampingDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CameraClampingDemoActivity.kt index 061b2b126..e55bca42c 100644 --- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CameraClampingDemoActivity.kt +++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CameraClampingDemoActivity.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. @@ -42,10 +42,6 @@ class CameraClampingDemoActivity : SamplesBaseActivity() { * Internal min zoom level that can be toggled via the demo. */ private var minZoom = DEFAULT_MIN_ZOOM - - /** - * Internal max zoom level that can be toggled via the demo. - */ private var maxZoom = DEFAULT_MAX_ZOOM @OptIn(ExperimentalCoroutinesApi::class) @@ -53,59 +49,80 @@ class CameraClampingDemoActivity : SamplesBaseActivity() { super.onCreate(savedInstanceState) binding = com.example.common_ui.databinding.CameraClampingDemoBinding.inflate(layoutInflater) setContentView(binding.root) + updateZoomLabel(minZoom, maxZoom) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment - lifecycleScope.launchWhenCreated { + lifecycleScope.launch { map = mapFragment.awaitMap() - launch { - map.cameraIdleEvents().collect { - onCameraIdle() - } + updateCameraPosition() + map.setOnCameraMoveListener { + updateCameraPosition() } - setButtonClickListeners() + map.setOnCameraIdleListener { + updateCameraPosition() + } + setControls() } - applyInsets(binding.mapContainer) } - private fun setButtonClickListeners() { - - binding.clampMinZoom.setOnClickListener { - minZoom += ZOOM_DELTA - // Constrains the minimum zoom level. - map.setMinZoomPreference(minZoom) - toast("Min zoom preference set to: $minZoom") - } - - binding.clampMaxZoom.setOnClickListener { - maxZoom -= ZOOM_DELTA - // Constrains the maximum zoom level. - map.setMaxZoomPreference(maxZoom) - toast("Max zoom preference set to: $maxZoom") + private fun setControls() { + binding.zoomRangeSlider.addOnChangeListener { slider, _, fromUser -> + val values = slider.values + minZoom = values[0] + maxZoom = values[1] + updateZoomLabel(minZoom, maxZoom) + if (fromUser && ::map.isInitialized) { + map.setMinZoomPreference(minZoom) + map.setMaxZoomPreference(maxZoom) + } } binding.clampZoomReset.setOnClickListener { resetMinMaxZoom() - map.resetMinMaxZoomPreference() + binding.zoomRangeSlider.setValues(DEFAULT_MIN_ZOOM, DEFAULT_MAX_ZOOM) + updateZoomLabel(DEFAULT_MIN_ZOOM, DEFAULT_MAX_ZOOM) + if (::map.isInitialized) { + map.resetMinMaxZoomPreference() + } toast("Min/Max zoom preferences reset.") } binding.clampLatlngAdelaide.setOnClickListener { + binding.latlngClampToggleGroup.check(R.id.clamp_latlng_adelaide) map.setLatLngBoundsForCameraTarget(ADELAIDE_BOUNDS) map.animateCamera(CameraUpdateFactory.newCameraPosition(ADELAIDE_CAMERA)) + binding.clampStatusText.text = getString(R.string.latlng_clamp_status_adelaide) } binding.clampLatlngPacific.setOnClickListener { + binding.latlngClampToggleGroup.check(R.id.clamp_latlng_pacific) map.setLatLngBoundsForCameraTarget(PACIFIC) map.animateCamera(CameraUpdateFactory.newCameraPosition(PACIFIC_CAMERA)) + binding.clampStatusText.text = getString(R.string.latlng_clamp_status_pacific) } binding.clampLatlngReset.setOnClickListener { + binding.latlngClampToggleGroup.clearChecked() map.setLatLngBoundsForCameraTarget(null) + binding.clampStatusText.text = getString(R.string.latlng_clamp_status_none) toast("LatLngBounds clamp reset.") } } - private fun onCameraIdle() { - binding.cameraText.text = map.cameraPosition.toString() + private fun updateZoomLabel(min: Float, max: Float) { + binding.zoomLabel.text = getString(R.string.zoom_bounds_label, min, max) + } + + private fun updateCameraPosition() { + if (!::map.isInitialized) return + val pos = map.cameraPosition + binding.cameraText.text = getString( + R.string.camera_position_format, + pos.target.latitude, + pos.target.longitude, + pos.zoom, + pos.tilt, + pos.bearing + ) } private fun toast(msg: String) { @@ -121,7 +138,7 @@ class CameraClampingDemoActivity : SamplesBaseActivity() { private val TAG = CameraClampingDemoActivity::class.java.name private const val ZOOM_DELTA = 2.0f private const val DEFAULT_MIN_ZOOM = 2.0f - private const val DEFAULT_MAX_ZOOM = 22.0f + private const val DEFAULT_MAX_ZOOM = 21.0f val ADELAIDE_BOUNDS = LatLngBounds( LatLng(-35.0, 138.58), LatLng(-34.9, 138.61)) private val ADELAIDE_CAMERA = CameraPosition.Builder() diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt index 5b4b75fb4..c48db2b93 100644 --- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt +++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018 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. @@ -18,6 +18,7 @@ package com.example.kotlindemos import android.os.Bundle import android.os.Handler +import android.os.Looper import android.os.SystemClock import android.view.View import android.view.animation.OvershootInterpolator @@ -121,7 +122,7 @@ class VisibleRegionDemoActivity : // this function smoothly changes the amount of padding over a period of time private fun animatePadding(toLeft: Int, toTop: Int, toRight: Int, toBottom: Int) { - val handler = Handler() + val handler = Handler(Looper.getMainLooper()) val start = SystemClock.uptimeMillis() val duration: Long = 1000 diff --git a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt index f316a9843..30b9c0bad 100644 --- a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt +++ b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/VisibleRegionDemoActivity.kt @@ -6,7 +6,7 @@ * corresponding file under the `app/src/gms` directory. */ /* - * Copyright 2018 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. @@ -25,6 +25,7 @@ package com.example.kotlindemos import android.os.Bundle import android.os.Handler +import android.os.Looper import android.os.SystemClock import android.view.View import android.view.animation.OvershootInterpolator @@ -131,7 +132,7 @@ class VisibleRegionDemoActivity : // this function smoothly changes the amount of padding over a period of time private fun animatePadding(toLeft: Int, toTop: Int, toRight: Int, toBottom: Int) { - val handler = Handler() + val handler = Handler(Looper.getMainLooper()) val start = SystemClock.uptimeMillis() val duration: Long = 1000