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/DataDrivenDatasetStylingActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
index 9173181a4..0b0bb4e84 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/DataDrivenDatasetStylingActivity.java
@@ -40,6 +40,7 @@
import com.google.android.gms.maps.model.FeatureStyle;
import com.google.android.gms.maps.model.FeatureType;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MapCapabilities;
import java.util.List;
@@ -58,8 +59,7 @@ public class DataDrivenDatasetStylingActivity extends SamplesBaseActivity implem
private record DataSet(
String label,
String datasetId,
- LatLng location,
- float zoomLevel,
+ LatLngBounds bounds,
DataDrivenDatasetStylingActivity.DataSet.StylingCallback callback) {
public interface StylingCallback {
void styleDatasetLayer();
@@ -71,25 +71,19 @@ public interface StylingCallback {
* Each DataSet contains:
* - A human-readable name (e.g., "Boulder", "New York").
* - A unique Dataset ID, which should correspond to a dataset id in the Datasets console tab.
- * - The central latitude and longitude coordinates (LatLng) of the location.
+ * - The LatLngBounds of the dataset area.
* - A styling function (method reference) that defines how to style the data from that dataset on a map.
- *
- * This array is used to configure which datasets are available for display and how they should be presented.
- * Each element of the array should be a new DataSet object.
- * Modify the constructor arguments of each DataSet to define your specific data and styles.
- * The styling function will receive a `Layer` to which it can add elements.
- *
- * Example:
- * - `new DataSet("Boulder", "Boulder-DataSet-Id", new LatLng(40.0150, -105.2705), this::styleBoulderDatasetLayer)`
- * This creates a DataSet for Boulder, identified by "Boulder-DataSet-Id", centered on the given coordinates,
- * and styled using the `styleBoulderDatasetLayer` method.
- *
- * Note: We have use the secrets plugin to allow us to configure the Dataset IDs in our secrets.properties file.
*/
private final DataSet[] dataSets = new DataSet[] {
- new DataSet("Boulder", BuildConfig.BOULDER_DATASET_ID, new LatLng(40.0150, -105.2705), 11f, this::styleBoulderDatasetLayer),
- new DataSet("New York", BuildConfig.NEW_YORK_DATASET_ID, new LatLng(40.786244, -73.962684), 14f, this::styleNYCDatasetLayer),
- new DataSet("Kyoto", BuildConfig.KYOTO_DATASET_ID, new LatLng(35.005081, 135.764385), 13.5f, this::styleKyotoDatasetsLayer),
+ new DataSet("Boulder", BuildConfig.BOULDER_DATASET_ID,
+ new LatLngBounds(new LatLng(39.920, -105.340), new LatLng(40.090, -105.210)),
+ this::styleBoulderDatasetLayer),
+ new DataSet("New York", BuildConfig.NEW_YORK_DATASET_ID,
+ new LatLngBounds(new LatLng(40.7640, -73.9820), new LatLng(40.8000, -73.9490)),
+ this::styleNYCDatasetLayer),
+ new DataSet("Kyoto", BuildConfig.KYOTO_DATASET_ID,
+ new LatLngBounds(new LatLng(34.9700, 135.7200), new LatLng(35.0400, 135.8000)),
+ this::styleKyotoDatasetsLayer),
};
private DataSet findDataSetByLabel(String label) {
@@ -176,7 +170,7 @@ private void switchDataSet(String label) {
.build()
);
dataSet.callback.styleDatasetLayer();
- centerMapOnLocation(dataSet.location(), dataSet.zoomLevel());
+ centerMapOnBounds(dataSet.bounds());
}
}
@@ -184,6 +178,11 @@ private void switchDataSet(String label) {
public void onMapReady(@NonNull GoogleMap googleMap) {
this.map = googleMap;
+ googleMap.setOnCameraIdleListener(() -> {
+ com.google.android.gms.maps.model.CameraPosition cp = googleMap.getCameraPosition();
+ Log.i(TAG, "CAMERA_PARAMS: target=LatLng(" + cp.target.latitude + ", " + cp.target.longitude + "), zoom=" + cp.zoom + "f, tilt=" + cp.tilt + "f, bearing=" + cp.bearing + "f");
+ });
+
MapCapabilities capabilities = map.getMapCapabilities();
Log.d(TAG, "Data-driven Styling is available: " + capabilities.isDataDrivenStylingAvailable());
if (!capabilities.isDataDrivenStylingAvailable()) {
@@ -364,8 +363,8 @@ private void styleBoulderDatasetLayer() {
}
- private void centerMapOnLocation(LatLng location, float zoomLevel) {
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, zoomLevel));
+ private void centerMapOnBounds(LatLngBounds bounds) {
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 80));
}
@Override
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/EventsDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/EventsDemoActivity.java
index 6699be4ee..f960dfa3f 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/EventsDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/EventsDemoActivity.java
@@ -25,6 +25,7 @@
import android.os.Bundle;
import android.widget.TextView;
+import java.util.Locale;
import androidx.appcompat.app.AppCompatActivity;
@@ -34,7 +35,7 @@
// [START maps_android_sample_events]
public class EventsDemoActivity extends SamplesBaseActivity
implements OnMapClickListener, OnMapLongClickListener, OnCameraIdleListener,
- OnMapReadyCallback {
+ GoogleMap.OnCameraMoveListener, OnMapReadyCallback {
private TextView tapTextView;
private TextView cameraTextView;
@@ -59,22 +60,51 @@ public void onMapReady(GoogleMap map) {
this.map = map;
this.map.setOnMapClickListener(this);
this.map.setOnMapLongClickListener(this);
+ this.map.setOnCameraMoveListener(this);
this.map.setOnCameraIdleListener(this);
+ updateCameraPosition();
}
@Override
public void onMapClick(LatLng point) {
- tapTextView.setText("tapped, point=" + point);
+ String lat = String.format(Locale.US, "%.6f", point.latitude);
+ String lng = String.format(Locale.US, "%.6f", point.longitude);
+ tapTextView.setText(getString(com.example.common_ui.R.string.events_tapped_format, lat, lng));
}
@Override
public void onMapLongClick(LatLng point) {
- tapTextView.setText("long pressed, point=" + point);
+ String lat = String.format(Locale.US, "%.6f", point.latitude);
+ String lng = String.format(Locale.US, "%.6f", point.longitude);
+ tapTextView.setText(getString(com.example.common_ui.R.string.events_long_pressed_format, lat, lng));
+ }
+
+ @Override
+ public void onCameraMove() {
+ updateCameraPosition();
}
@Override
public void onCameraIdle() {
- cameraTextView.setText(map.getCameraPosition().toString());
+ updateCameraPosition();
+ }
+
+ private void updateCameraPosition() {
+ if (map == null) return;
+ com.google.android.gms.maps.model.CameraPosition pos = map.getCameraPosition();
+ String lat = String.format(Locale.US, "%.6f", pos.target.latitude);
+ String lng = String.format(Locale.US, "%.6f", pos.target.longitude);
+ String zoom = String.format(Locale.US, "%.1f", pos.zoom);
+ String tilt = String.format(Locale.US, "%.1f", pos.tilt);
+ String bearing = String.format(Locale.US, "%.1f", pos.bearing);
+ cameraTextView.setText(getString(
+ com.example.common_ui.R.string.events_camera_position_format,
+ lat,
+ lng,
+ zoom,
+ tilt,
+ bearing
+ ));
}
}
// [END maps_android_sample_events]
\ No newline at end of file
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
index 3d54aa420..d29df321e 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/GroundOverlayDemoActivity.java
@@ -23,6 +23,7 @@
import com.google.android.gms.maps.model.GroundOverlay;
import com.google.android.gms.maps.model.GroundOverlayOptions;
import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
import android.graphics.Point;
import android.os.Bundle;
@@ -51,6 +52,10 @@ public class GroundOverlayDemoActivity extends SamplesBaseActivity
private static final LatLng NEWARK = new LatLng(40.714086, -74.228697);
private static final LatLng NEAR_NEWARK =
new LatLng(NEWARK.latitude - 0.001, NEWARK.longitude - 0.025);
+ static final LatLngBounds OVERLAY_BOUNDS = new LatLngBounds(
+ new LatLng(40.7050, -74.2600),
+ new LatLng(40.7800, -74.1200)
+ );
private final List images = new ArrayList<>();
@@ -84,7 +89,7 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(binding.getRoot());
binding.transparencySeekBar.setMax(TRANSPARENCY_MAX);
- binding.transparencySeekBar.setProgress(0);
+ binding.transparencySeekBar.setProgress(25);
// Set up programmatic click listeners for the buttons.
binding.switchImage.setOnClickListener(v -> switchImage());
@@ -106,10 +111,8 @@ public void onMapReady(GoogleMap map) {
// Register a listener to respond to clicks on GroundOverlays.
map.setOnGroundOverlayClickListener(this);
- // Move the camera to the Newark area.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11));
-
- map.moveCamera(CameraUpdateFactory.scrollBy(100f, 100f));
+ // Move the camera to frame the Newark overlays with padding.
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(OVERLAY_BOUNDS, 80));
map.setOnMapClickListener(ll -> {
Point point = mMap.getProjection().toScreenLocation(ll);
@@ -141,7 +144,8 @@ public void onMapReady(GoogleMap map) {
// Add a large overlay at Newark on top of the smaller overlay.
groundOverlay = map.addGroundOverlay(new GroundOverlayOptions()
.image(images.get(currentEntry)).anchor(0, 1)
- .position(NEWARK, 8600f, 6500f));
+ .position(NEWARK, 8600f, 6500f)
+ .transparency((float) binding.transparencySeekBar.getProgress() / (float) TRANSPARENCY_MAX));
groundOverlay.setTag(images.get(currentEntry));
binding.transparencySeekBar.setOnSeekBarChangeListener(this);
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LayersDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LayersDemoActivity.java
index c10f19823..c992290f0 100755
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LayersDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LayersDemoActivity.java
@@ -88,6 +88,15 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void onMapReady(GoogleMap map) {
mMap = map;
+
+ com.google.android.gms.maps.model.CameraPosition initialPosition =
+ new com.google.android.gms.maps.model.CameraPosition.Builder()
+ .target(new com.google.android.gms.maps.model.LatLng(-33.8688, 151.2093))
+ .zoom(16.5f)
+ .tilt(40.0f)
+ .build();
+ mMap.moveCamera(com.google.android.gms.maps.CameraUpdateFactory.newCameraPosition(initialPosition));
+
updateMapType();
updateTraffic();
updateMyLocation();
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java
index e2638c915..40e0146eb 100755
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LiteListDemoActivity.java
@@ -31,6 +31,7 @@
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -52,6 +53,9 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.example.common_ui.R.layout.lite_list_demo);
+ Toolbar toolbar = findViewById(com.example.common_ui.R.id.top_bar);
+ setSupportActionBar(toolbar);
+
mGridLayoutManager = new GridLayoutManager(this, 2);
mLinearLayoutManager = new LinearLayoutManager(this);
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java
index d3e3fd53b..93bddddc3 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/LocationSourceDemoActivity.java
@@ -90,6 +90,11 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.example.common_ui.R.layout.basic_demo);
+ androidx.appcompat.widget.Toolbar toolbar = findViewById(com.example.common_ui.R.id.top_bar);
+ if (toolbar != null) {
+ toolbar.setTitle(com.example.common_ui.R.string.location_source_demo_label);
+ }
+
mLocationSource = new LongPressLocationSource();
SupportMapFragment mapFragment =
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java
index b3609b4c4..9a0e53e22 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/MarkerDemoActivity.java
@@ -36,6 +36,7 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import com.example.common_ui.R;
@@ -429,7 +430,7 @@ public void onStopTrackingTouch(SeekBar seekBar) {
public boolean onMarkerClick(final Marker marker) {
if (marker.equals(mPerth)) {
// This causes the marker at Perth to bounce into position when it is clicked.
- final Handler handler = new Handler();
+ final Handler handler = new Handler(Looper.getMainLooper());
final long start = SystemClock.uptimeMillis();
final long duration = 1500;
@@ -485,17 +486,17 @@ public void onInfoWindowLongClick(Marker marker) {
@Override
public void onMarkerDragStart(Marker marker) {
- binding.topText.setText("onMarkerDragStart");
+ binding.topText.setText(R.string.on_marker_drag_start);
}
@Override
public void onMarkerDragEnd(Marker marker) {
- binding.topText.setText("onMarkerDragEnd");
+ binding.topText.setText(R.string.on_marker_drag_end);
}
@Override
public void onMarkerDrag(Marker marker) {
- binding.topText.setText("onMarkerDrag. Current Position: " + marker.getPosition());
+ binding.topText.setText(getString(R.string.on_marker_drag, marker.getPosition().latitude, marker.getPosition().longitude));
}
}
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SamplesBaseActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SamplesBaseActivity.java
index 6a1518dcb..8ad832441 100644
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SamplesBaseActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SamplesBaseActivity.java
@@ -18,6 +18,8 @@
import android.os.Bundle;
import android.view.View;
+import android.view.ViewGroup;
+
import androidx.activity.EdgeToEdge;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@@ -33,18 +35,67 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
EdgeToEdge.enable(this);
}
+ @Override
+ public void setContentView(int layoutResID) {
+ super.setContentView(layoutResID);
+ setupEdgeToEdgeInsets();
+ }
+
+ @Override
+ public void setContentView(View view) {
+ super.setContentView(view);
+ setupEdgeToEdgeInsets();
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ super.setContentView(view, params);
+ setupEdgeToEdgeInsets();
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ super.addContentView(view, params);
+ setupEdgeToEdgeInsets();
+ }
+
+ private void setupEdgeToEdgeInsets() {
+ View root = findViewById(android.R.id.content);
+ if (root == null) return;
+ View topBar = root.findViewById(com.example.common_ui.R.id.top_bar);
+ if (topBar != null) {
+ android.util.TypedValue typedValue = new android.util.TypedValue();
+ int baseHeight;
+ if (getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)) {
+ baseHeight = android.util.TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics());
+ } else {
+ baseHeight = (int) (56 * getResources().getDisplayMetrics().density);
+ }
+ ViewCompat.setOnApplyWindowInsetsListener(topBar, (view, insets) -> {
+ Insets statusBar = insets.getInsets(WindowInsetsCompat.Type.statusBars() | WindowInsetsCompat.Type.displayCutout());
+ view.setPadding(statusBar.left, statusBar.top, statusBar.right, 0);
+ view.getLayoutParams().height = baseHeight + statusBar.top;
+ view.requestLayout();
+ return insets;
+ });
+ }
+
+ View mapContainer = root.findViewById(com.example.common_ui.R.id.map_container);
+ View bottomTarget = mapContainer != null ? mapContainer : root;
+ ViewCompat.setOnApplyWindowInsetsListener(bottomTarget, (view, insets) -> {
+ Insets navBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars() | WindowInsetsCompat.Type.displayCutout());
+ int topInsets = (topBar == null) ? insets.getInsets(WindowInsetsCompat.Type.statusBars()).top : 0;
+ view.setPadding(navBars.left, topInsets, navBars.right, navBars.bottom);
+ return insets;
+ });
+ }
+
/**
* Applies insets to the container view to properly handle window insets.
*
* @param container the container view to apply insets to
*/
protected static void applyInsets(View container) {
- ViewCompat.setOnApplyWindowInsetsListener(container,
- (view, insets) -> {
- Insets innerPadding = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
- view.setPadding(innerPadding.left, innerPadding.top, innerPadding.right, innerPadding.bottom);
- return insets;
- }
- );
+ // Handled automatically in SamplesBaseActivity
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java
index a297cf8af..b0fbce046 100755
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SnapshotDemoActivity.java
@@ -15,11 +15,13 @@
package com.example.mapdemo;
+import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;
import com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.LatLng;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -27,18 +29,26 @@
import android.widget.CheckBox;
import android.widget.ImageView;
-import androidx.appcompat.app.AppCompatActivity;
+import androidx.annotation.NonNull;
/**
- * This shows how to take a snapshot of the map.
+ * Demonstrates capturing a bitmap screenshot of a {@link GoogleMap} view using {@link GoogleMap#snapshot}.
+ *
+ * Key Concepts:
+ * 1. Live Map Capture: {@link GoogleMap#snapshot} takes an asynchronous render of the current
+ * map viewport and delivers it as an Android {@link Bitmap} via {@link SnapshotReadyCallback}.
+ * 2. Tile Readiness Synchronization: If the "Wait for Map Load" option is selected,
+ * {@link GoogleMap#setOnMapLoadedCallback} is invoked first to ensure all vector tiles, labels,
+ * and overlays are fully rendered before capturing the bitmap.
+ * 3. Material 3 Split View: Displays the interactive map in a top card and the captured
+ * preview in a bottom card with empty-state placeholder handling.
*/
public class SnapshotDemoActivity extends SamplesBaseActivity implements OnMapReadyCallback {
- /**
- * Note that this may be null if the Google Play services APK is not available.
- */
- private GoogleMap mMap;
+ // Venice, Italy (Grand Canal & Rialto)
+ static final LatLng VENICE = new LatLng(45.4380, 12.3350);
+ private GoogleMap mMap;
private com.example.common_ui.databinding.SnapshotDemoBinding binding;
@Override
@@ -52,14 +62,17 @@ protected void onCreate(Bundle savedInstanceState) {
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map);
+ assert mapFragment != null;
mapFragment.getMapAsync(this);
applyInsets(binding.mapContainer);
}
@Override
- public void onMapReady(GoogleMap map) {
- mMap = map;
+ public void onMapReady(@NonNull GoogleMap map) {
+ this.mMap = map;
+ // Center on Venice, Italy — a visually rich standard vector map showing the Grand Canal and Rialto
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(VENICE, 14.5f));
}
private void takeSnapshot() {
@@ -72,8 +85,10 @@ private void takeSnapshot() {
final SnapshotReadyCallback callback = new SnapshotReadyCallback() {
@Override
public void onSnapshotReady(Bitmap snapshot) {
- // Callback is called from the main thread, so we can modify the ImageView safely.
+ // Callback is called from the main thread, so we can modify the ImageView and cards safely.
snapshotHolder.setImageBitmap(snapshot);
+ binding.snapshotPlaceholder.setVisibility(View.GONE);
+ binding.snapshotLabel.setVisibility(View.VISIBLE);
}
};
@@ -91,5 +106,7 @@ public void onMapLoaded() {
private void clearSnapshot() {
binding.snapshotHolder.setImageDrawable(null);
+ binding.snapshotPlaceholder.setVisibility(View.VISIBLE);
+ binding.snapshotLabel.setVisibility(View.GONE);
}
}
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java
index 2ff30e18a..26c749dca 100755
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/SplitStreetViewPanoramaAndMapDemoActivity.java
@@ -15,6 +15,22 @@
package com.example.mapdemo;
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+
+import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.location.Priority;
+import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener;
import com.google.android.gms.maps.OnMapReadyCallback;
@@ -28,30 +44,45 @@
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.StreetViewPanoramaLocation;
-
-import android.os.Bundle;
-
-import androidx.appcompat.app.AppCompatActivity;
+import com.google.android.gms.tasks.CancellationTokenSource;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
/**
- * This shows how to create a simple activity with streetview and a map
+ * Demonstrates bidirectional synchronization between a {@link SupportStreetViewPanoramaFragment}
+ * (top pane) and a {@link SupportMapFragment} (bottom pane).
+ *
+ * Key concepts illustrated:
+ * 1. **Map-to-Street View Sync**: Long-pressing and dragging the yellow "Pegman" marker on the map
+ * updates the Street View panorama to match the new drop coordinates.
+ * 2. **Street View-to-Map Sync**: Navigating within Street View (tapping forward arrows/chevrons)
+ * updates Pegman's position on the map and smoothly pans the map camera to follow.
+ * 3. **High-Accuracy Location**: Uses {@link FusedLocationProviderClient} with {@link Priority#PRIORITY_HIGH_ACCURACY}
+ * to teleport Pegman and Street View to the user's real-time physical location on demand.
*/
public class SplitStreetViewPanoramaAndMapDemoActivity extends SamplesBaseActivity
- implements OnMarkerDragListener, OnStreetViewPanoramaChangeListener {
+ implements OnMarkerDragListener, OnStreetViewPanoramaChangeListener,
+ ActivityCompat.OnRequestPermissionsResultCallback {
+ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
private static final String MARKER_POSITION_KEY = "MarkerPosition";
- // George St, Sydney
+ // Default start location: George St, Sydney, Australia
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
private StreetViewPanorama streetViewPanorama;
-
+ private GoogleMap map;
private Marker marker;
+ private FusedLocationProviderClient fusedLocationClient;
+ private CancellationTokenSource cancellationTokenSource;
+ private boolean permissionRequested = false;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.example.common_ui.R.layout.split_street_view_panorama_and_map_demo);
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
final LatLng markerPosition;
if (savedInstanceState == null) {
@@ -60,6 +91,7 @@ protected void onCreate(final Bundle savedInstanceState) {
markerPosition = savedInstanceState.getParcelable(MARKER_POSITION_KEY);
}
+ // Initialize the Street View fragment (top pane)
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.streetviewpanorama);
@@ -70,50 +102,232 @@ public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
streetViewPanorama = panorama;
streetViewPanorama.setOnStreetViewPanoramaChangeListener(
SplitStreetViewPanoramaAndMapDemoActivity.this);
- // Only need to set the position once as the streetview fragment will maintain
- // its state.
+ // Street View maintains its own state across orientation changes; only set position initially.
if (savedInstanceState == null) {
streetViewPanorama.setPosition(SYDNEY);
}
}
});
+ // Initialize the Google Map fragment (bottom pane)
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
+ @SuppressLint("MissingPermission")
@Override
- public void onMapReady(GoogleMap map) {
- map.setOnMarkerDragListener(SplitStreetViewPanoramaAndMapDemoActivity.this);
- // Creates a draggable marker. Long press to drag.
- marker = map.addMarker(new MarkerOptions()
+ public void onMapReady(GoogleMap googleMap) {
+ map = googleMap;
+ // Center map camera on Pegman's location with street-level zoom
+ googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerPosition, 16f));
+ googleMap.setOnMarkerDragListener(SplitStreetViewPanoramaAndMapDemoActivity.this);
+
+ // Hide the default top-right map button in favor of the unified Material FAB
+ googleMap.getUiSettings().setMyLocationButtonEnabled(false);
+ if (hasLocationPermission()) {
+ googleMap.setMyLocationEnabled(true);
+ }
+
+ // Create a draggable Pegman marker on the map
+ marker = googleMap.addMarker(new MarkerOptions()
.position(markerPosition)
.icon(BitmapDescriptorFactory.fromResource(com.example.common_ui.R.drawable.pegman))
.draggable(true));
}
});
+
+ // Material FAB to locate the user and jump Pegman to their neighborhood
+ FloatingActionButton btnMyLocation = findViewById(com.example.common_ui.R.id.btn_my_location);
+ if (btnMyLocation != null) {
+ btnMyLocation.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ moveToMyLocation();
+ }
+ });
+ }
applyInsets(findViewById(com.example.common_ui.R.id.map_container));
}
+ /**
+ * Checks if fine or coarse location permission is granted.
+ */
+ private boolean hasLocationPermission() {
+ return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED
+ || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Requests high-accuracy live location via {@link FusedLocationProviderClient} and teleports
+ * Pegman, the map camera, and Street View to the user's location.
+ */
+ @SuppressLint("MissingPermission")
+ private void moveToMyLocation() {
+ if (!hasLocationPermission()) {
+ if (permissionRequested && !ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION
+ ) && !ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_COARSE_LOCATION
+ )) {
+ // Permanently denied ("Don't ask again") -> show informative toast guidance
+ Toast.makeText(
+ this,
+ com.example.common_ui.R.string.location_permission_required_toast,
+ Toast.LENGTH_LONG
+ ).show();
+ } else {
+ permissionRequested = true;
+ PermissionUtils.requestLocationPermissions(this, LOCATION_PERMISSION_REQUEST_CODE, false);
+ }
+ return;
+ }
+
+ if (map != null) {
+ map.setMyLocationEnabled(true);
+ }
+ Toast.makeText(this, getString(com.example.common_ui.R.string.getting_location), Toast.LENGTH_SHORT).show();
+
+ // Cancel any pending active location request
+ if (cancellationTokenSource != null) {
+ cancellationTokenSource.cancel();
+ }
+ cancellationTokenSource = new CancellationTokenSource();
+
+ // Actively query NLP / GNSS for the current high-accuracy position
+ fusedLocationClient.getCurrentLocation(
+ Priority.PRIORITY_HIGH_ACCURACY,
+ cancellationTokenSource.getToken()
+ ).addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(Location location) {
+ if (location != null) {
+ updatePositionToLocation(location);
+ } else {
+ // Fallback to last known cached location if live fix is temporarily unavailable
+ fusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener() {
+ @Override
+ public void onSuccess(Location fallbackLocation) {
+ if (fallbackLocation != null) {
+ updatePositionToLocation(fallbackLocation);
+ } else {
+ Toast.makeText(SplitStreetViewPanoramaAndMapDemoActivity.this,
+ getString(com.example.common_ui.R.string.waiting_for_location),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ }).addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ Toast.makeText(SplitStreetViewPanoramaAndMapDemoActivity.this,
+ getString(com.example.common_ui.R.string.waiting_for_location),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+ }).addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ Toast.makeText(SplitStreetViewPanoramaAndMapDemoActivity.this,
+ getString(com.example.common_ui.R.string.waiting_for_location),
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ /**
+ * Updates Pegman's position, centers the map camera, and looks up the closest
+ * Street View panorama within a 200m radius of the user coordinates.
+ */
+ private void updatePositionToLocation(Location location) {
+ LatLng userLatLng = new LatLng(location.getLatitude(), location.getLongitude());
+ if (marker != null) {
+ marker.setPosition(userLatLng);
+ }
+ if (map != null) {
+ map.animateCamera(CameraUpdateFactory.newLatLngZoom(userLatLng, 16f));
+ }
+ if (streetViewPanorama != null) {
+ streetViewPanorama.setPosition(userLatLng, 200);
+ }
+ Toast.makeText(this, getString(com.example.common_ui.R.string.moved_pegman_to_location), Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ return;
+ }
+ if (PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION)
+ || PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION)) {
+ moveToMyLocation();
+ } else {
+ if (!ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION
+ )) {
+ Toast.makeText(
+ this,
+ com.example.common_ui.R.string.location_permission_required_toast,
+ Toast.LENGTH_LONG
+ ).show();
+ }
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (cancellationTokenSource != null) {
+ cancellationTokenSource.cancel();
+ }
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putParcelable(MARKER_POSITION_KEY, marker.getPosition());
+ if (marker != null) {
+ outState.putParcelable(MARKER_POSITION_KEY, marker.getPosition());
+ }
}
+ // --- Street View -> Map Synchronization ---
+
+ /**
+ * Called when the user navigates within the Street View panorama (e.g. stepping down a road).
+ * Synchronizes Pegman's position on the map and smoothly pans the camera.
+ */
@Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation location) {
if (location != null) {
- marker.setPosition(location.position);
+ if (marker != null) {
+ marker.setPosition(location.position);
+ }
+ if (map != null) {
+ map.animateCamera(CameraUpdateFactory.newLatLng(location.position));
+ }
}
}
+ // --- Map -> Street View Synchronization ---
+
@Override
public void onMarkerDragStart(Marker marker) {
}
+ /**
+ * Called when the user finishes dragging Pegman on the map.
+ * Snaps the Street View panorama to the new drop location within a 150m search radius.
+ */
@Override
public void onMarkerDragEnd(Marker marker) {
- streetViewPanorama.setPosition(marker.getPosition(), 150);
+ if (streetViewPanorama != null) {
+ streetViewPanorama.setPosition(marker.getPosition(), 150);
+ }
+ if (map != null) {
+ map.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()));
+ }
}
@Override
diff --git a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java
index ad03fb251..2215cb997 100755
--- a/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java
+++ b/ApiDemos/project/java-app/src/main/java/com/example/mapdemo/StreetViewPanoramaEventsDemoActivity.java
@@ -98,13 +98,13 @@ protected void onCreate(final Bundle savedInstanceState) {
@Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation location) {
if (location != null) {
- panoChangeTimesTextView.setText("Times panorama changed=" + ++panoChangeTimes);
+ panoChangeTimesTextView.setText(getString(com.example.common_ui.R.string.pano_change_times, ++panoChangeTimes));
}
}
@Override
public void onStreetViewPanoramaCameraChange(StreetViewPanoramaCamera camera) {
- panoCameraChangeTextView.setText("Times camera changed=" + ++panoCameraChangeTimes);
+ panoCameraChangeTextView.setText(getString(com.example.common_ui.R.string.pano_camera_change_times, ++panoCameraChangeTimes));
}
@Override
@@ -113,7 +113,7 @@ public void onStreetViewPanoramaClick(StreetViewPanoramaOrientation orientation)
if (point != null) {
panoClickTimes++;
panoClickTextView.setText(
- "Times clicked=" + panoClickTimes + " : " + point);
+ getString(com.example.common_ui.R.string.pano_click_times, panoClickTimes, point));
streetViewPanorama.animateTo(
new StreetViewPanoramaCamera.Builder()
.orientation(orientation)
@@ -128,7 +128,7 @@ public void onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation orientat
if (point != null) {
panoLongClickTimes++;
panoLongClickTextView.setText(
- "Times long clicked=" + panoLongClickTimes + " : " + point);
+ getString(com.example.common_ui.R.string.pano_long_click_times, panoLongClickTimes, point));
}
}
}
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..2ba5e00e5 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
@@ -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/MarkerDemoActivity.java b/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/MarkerDemoActivity.java
index 79c5a1f64..a5d207556 100644
--- a/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/MarkerDemoActivity.java
+++ b/ApiDemos/project/java-app/src/v3/java/com/example/mapdemo/MarkerDemoActivity.java
@@ -37,6 +37,7 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
@@ -435,7 +436,7 @@ public void onStopTrackingTouch(SeekBar seekBar) {
public boolean onMarkerClick(final Marker marker) {
if (marker.equals(mPerth)) {
// This causes the marker at Perth to bounce into position when it is clicked.
- final Handler handler = new Handler();
+ final Handler handler = new Handler(Looper.getMainLooper());
final long start = SystemClock.uptimeMillis();
final long duration = 1500;
@@ -491,17 +492,17 @@ public void onInfoWindowLongClick(Marker marker) {
@Override
public void onMarkerDragStart(Marker marker) {
- mTopText.setText("onMarkerDragStart");
+ mTopText.setText(com.example.common_ui.R.string.on_marker_drag_start);
}
@Override
public void onMarkerDragEnd(Marker marker) {
- mTopText.setText("onMarkerDragEnd");
+ mTopText.setText(com.example.common_ui.R.string.on_marker_drag_end);
}
@Override
public void onMarkerDrag(Marker marker) {
- mTopText.setText("onMarkerDrag. Current Position: " + marker.getPosition());
+ mTopText.setText(getString(com.example.common_ui.R.string.on_marker_drag, marker.getPosition().latitude, marker.getPosition().longitude));
}
}
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..c2d8f7437 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
@@ -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/build.gradle.kts b/ApiDemos/project/kotlin-app/build.gradle.kts
index 810fa6e18..f8495cb4b 100644
--- a/ApiDemos/project/kotlin-app/build.gradle.kts
+++ b/ApiDemos/project/kotlin-app/build.gradle.kts
@@ -43,6 +43,7 @@ android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
+ isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@@ -84,6 +85,7 @@ dependencies {
implementation(libs.lifecycle.runtime.ktx)
implementation(libs.maps.ktx)
implementation(libs.maps.utils.ktx)
+ implementation(libs.play.services.location)
implementation(libs.activity)
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
index 515dfa49c..b9efe9af4 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/AdvancedMarkersDemoActivity.kt
@@ -14,6 +14,7 @@
package com.example.kotlindemos
import android.graphics.Color
+import androidx.core.graphics.toColorInt
import com.google.android.gms.maps.OnMapReadyCallback
import android.os.Bundle
@@ -27,6 +28,7 @@ import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.model.AdvancedMarkerOptions
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MapCapabilities
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.PinConfig
@@ -137,83 +139,93 @@ class AdvancedMarkersDemoActivity : SamplesBaseActivity(), OnMapReadyCallback {
override fun onMapReady(map: GoogleMap) {
- with(map) {
- moveCamera(CameraUpdateFactory.newLatLngZoom(SINGAPORE, ZOOM_LEVEL))
- }
+ val bounds = LatLngBounds.builder()
+ .include(SINGAPORE)
+ .include(KUALA_LUMPUR)
+ .include(JAKARTA)
+ .include(BANGKOK)
+ .include(MANILA)
+ .include(HO_CHI_MINH_CITY)
+ .build()
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 120))
val capabilities: MapCapabilities = map.mapCapabilities
Log.d(TAG, "are advanced marker enabled?" + capabilities.isAdvancedMarkersAvailable)
- // This sample sets a view as the iconView for the Advanced Marker
- val textView = TextView(this)
- textView.text = "Hello!"
- val advancedMarkerView: Marker? = map.addMarker(
- AdvancedMarkerOptions().position(SINGAPORE).iconView(textView).zIndex(1f)
+ // 1. Custom View as iconView (Framed circular badge with Android logo)
+ val iconImageView = android.widget.ImageView(this).apply {
+ setImageResource(R.drawable.ic_android)
+ setColorFilter("#3DDC84".toColorInt()) // Android Green
+ setBackgroundResource(R.drawable.bg_marker_badge)
+ val padding = (8 * resources.displayMetrics.density).toInt()
+ setPadding(padding, padding, padding, padding)
+ layoutParams = android.view.ViewGroup.LayoutParams(
+ (44 * resources.displayMetrics.density).toInt(),
+ (44 * resources.displayMetrics.density).toInt()
+ )
+ }
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .position(SINGAPORE)
+ .iconView(iconImageView)
+ .title("Singapore (Custom Framed Badge)")
+ .zIndex(1f)
)
- // This uses PinConfig.Builder to create an instance of PinConfig.
- val pinConfigBuilder: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder.setBackgroundColor(Color.MAGENTA)
- val pinConfig: PinConfig = pinConfigBuilder.build()
-
-
- // Use the PinConfig instance to set the icon for AdvancedMarkerOptions.
- val advancedMarkerOptions: AdvancedMarkerOptions =
- AdvancedMarkerOptions().icon(BitmapDescriptorFactory.fromPinConfig(pinConfig))
+ // 2. PinConfig with custom background color
+ val pinConfigMagenta = PinConfig.builder()
+ .setBackgroundColor(Color.MAGENTA)
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigMagenta))
.position(KUALA_LUMPUR)
+ .title("Kuala Lumpur (Magenta Pin)")
+ )
+ // 3. PinConfig with custom border color
+ val pinConfigBorder = PinConfig.builder()
+ .setBorderColor(Color.BLUE)
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigBorder))
+ .position(JAKARTA)
+ .title("Jakarta (Blue Border)")
+ )
- // Pass the AdvancedMarkerOptions instance to addMarker().
- val marker: Marker? = map.addMarker(advancedMarkerOptions)
-
- // This sample changes the border color of the advanced marker
- val pinConfigBuilder2: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder2.setBorderColor(Color.BLUE)
- val pinConfig2: PinConfig = pinConfigBuilder2.build()
-
- val advancedMarkerOptions2: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig2))
- .position(JAKARTA)
-
-
- val marker2: Marker? = map.addMarker(advancedMarkerOptions2)
-
- // Set the glyph text.
- val pinConfigBuilder3: PinConfig.Builder = PinConfig.builder()
- val glyphText = PinConfig.Glyph("A")
-
- // Alternatively, you can set the text color:
- // Glyph glyphText = new Glyph("A", Color.GREEN);
- pinConfigBuilder3.setGlyph(glyphText)
- val pinConfig3: PinConfig = pinConfigBuilder3.build()
-
- val advancedMarkerOptions3: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig3))
- .position(BANGKOK)
-
- val marker3: Marker? = map.addMarker(advancedMarkerOptions3)
-
- // Create a transparent glyph.
- val pinConfigBuilder4: PinConfig.Builder = PinConfig.builder()
- pinConfigBuilder4.setBackgroundColor(Color.MAGENTA)
- pinConfigBuilder4.setGlyph(PinConfig.Glyph(Color.TRANSPARENT))
- val pinConfig4: PinConfig = pinConfigBuilder4.build()
-
- val advancedMarkerOptions4: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .icon(BitmapDescriptorFactory.fromPinConfig(pinConfig4))
- .position(MANILA)
+ // 4. PinConfig with text glyph ("A")
+ val pinConfigTextGlyph = PinConfig.builder()
+ .setGlyph(PinConfig.Glyph("A"))
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigTextGlyph))
+ .position(BANGKOK)
+ .title("Bangkok (Text Glyph 'A')")
+ )
- val marker4: Marker? = map.addMarker(advancedMarkerOptions4)
+ // 5. PinConfig with transparent glyph (cutout / donut pin)
+ val pinConfigHole = PinConfig.builder()
+ .setBackgroundColor(Color.MAGENTA)
+ .setGlyph(PinConfig.Glyph(Color.TRANSPARENT))
+ .build()
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .icon(BitmapDescriptorFactory.fromPinConfig(pinConfigHole))
+ .position(MANILA)
+ .title("Manila (Transparent Cutout Glyph)")
+ )
- // Collision behavior can only be changed in the AdvancedMarkerOptions object.
- // Changes to collision behavior after a marker has been created are not possible
- val collisionBehavior: Int =
+ // 6. Collision behavior
+ val collisionBehavior =
AdvancedMarkerOptions.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL
- val advancedMarkerOptions5: AdvancedMarkerOptions = AdvancedMarkerOptions()
- .position(HO_CHI_MINH_CITY)
- .collisionBehavior(collisionBehavior)
-
- val marker5: Marker? = map.addMarker(advancedMarkerOptions5)
+ map.addMarker(
+ AdvancedMarkerOptions()
+ .position(HO_CHI_MINH_CITY)
+ .collisionBehavior(collisionBehavior)
+ .title("Ho Chi Minh City (Collision Behavior)")
+ )
}
}
// [END maps_android_sample_marker_advanced]
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationDemoActivity.kt
index 417051e6e..e8beb83f5 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationDemoActivity.kt
@@ -33,7 +33,7 @@ class BackgroundColorCustomizationDemoActivity : SamplesBaseActivity(), OnMapRea
setContentView(R.layout.background_color_customization_demo)
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
/**
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationProgrammaticDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationProgrammaticDemoActivity.kt
index 11d39d4da..df4fca3c7 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationProgrammaticDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/BackgroundColorCustomizationProgrammaticDemoActivity.kt
@@ -58,7 +58,7 @@ class BackgroundColorCustomizationProgrammaticDemoActivity : SamplesBaseActivity
} else {
mapFragment.getMapAsync(this)
}
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(map: GoogleMap) {
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..e0c4de4e2 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
@@ -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/CloudBasedMapStylingDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CloudBasedMapStylingDemoActivity.kt
index 3622e4cd3..a6f1242d3 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CloudBasedMapStylingDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/CloudBasedMapStylingDemoActivity.kt
@@ -50,7 +50,7 @@ class CloudBasedMapStylingDemoActivity : SamplesBaseActivity(), OnMapReadyCallba
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment!!.getMapAsync(this)
setUpButtonListeners()
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(map: GoogleMap) {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenBoundariesActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenBoundariesActivity.kt
index 26d0c7d82..f380ca76a 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenBoundariesActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenBoundariesActivity.kt
@@ -107,7 +107,7 @@ class DataDrivenBoundariesActivity : SamplesBaseActivity(), OnMapReadyCallback,
setupBoundarySelectorButton() // Setup the new selector button
// --- Insets ---
- applyInsets(findViewById(R.id.map_container)) // Apply insets if needed
+ applyInsets(findViewById(R.id.map_container)) // Apply insets if needed
}
private fun setupBoundarySelectorButton() {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
index 62656c2f4..c93052975 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/DataDrivenDatasetStylingActivity.kt
@@ -27,6 +27,7 @@ import android.widget.LinearLayout
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.annotation.ColorInt
+import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.GoogleMap
@@ -39,6 +40,7 @@ import com.google.android.gms.maps.model.FeatureLayerOptions
import com.google.android.gms.maps.model.FeatureStyle
import com.google.android.gms.maps.model.FeatureType
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.MapCapabilities
import androidx.core.view.WindowCompat
import com.google.android.gms.maps.GoogleMapOptions
@@ -55,7 +57,6 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
private lateinit var mapContainer: ViewGroup
private lateinit var map: GoogleMap
- private val zoomLevel = 13.5f
private var datasetLayer: FeatureLayer? = null
@@ -64,7 +65,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
private data class DataSet(
val datasetId: String,
- val location: LatLng,
+ val bounds: LatLngBounds,
val callback: DataDrivenDatasetStylingActivity.() -> Unit
)
@@ -86,9 +87,27 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
if (dataSets.isEmpty()) {
with(dataSets) {
- put(getString(com.example.common_ui.R.string.boulder), DataSet(BuildConfig.BOULDER_DATASET_ID, LatLng(40.0150, -105.2705)) { styleBoulderDataset() })
- put(getString(com.example.common_ui.R.string.new_york), DataSet(BuildConfig.NEW_YORK_DATASET_ID, LatLng(40.786244, -73.962684)) { styleNYCDataset() })
- put(getString(com.example.common_ui.R.string.kyoto), DataSet(BuildConfig.KYOTO_DATASET_ID, LatLng(35.005081, 135.764385)) { styleKyotoDataset() })
+ put(
+ getString(com.example.common_ui.R.string.boulder),
+ DataSet(
+ BuildConfig.BOULDER_DATASET_ID,
+ LatLngBounds(LatLng(39.920, -105.340), LatLng(40.090, -105.210))
+ ) { styleBoulderDataset() }
+ )
+ put(
+ getString(com.example.common_ui.R.string.new_york),
+ DataSet(
+ BuildConfig.NEW_YORK_DATASET_ID,
+ LatLngBounds(LatLng(40.7640, -73.9820), LatLng(40.8000, -73.9490))
+ ) { styleNYCDataset() }
+ )
+ put(
+ getString(com.example.common_ui.R.string.kyoto),
+ DataSet(
+ BuildConfig.KYOTO_DATASET_ID,
+ LatLngBounds(LatLng(34.9700, 135.7200), LatLng(35.0400, 135.8000))
+ ) { styleKyotoDataset() }
+ )
}
}
@@ -124,7 +143,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
buttonLayout = findViewById(com.example.common_ui.R.id.button_kyoto).parent as LinearLayout
handleCutout()
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
}
private fun handleCutout() {
@@ -139,6 +158,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}
} else {
window.decorView.setOnApplyWindowInsetsListener { view, windowInsets ->
+ @Suppress("DEPRECATION")
val topInset = windowInsets.systemWindowInsetTop
mapContainer.setPadding(0, topInset, 0, 0)
windowInsets
@@ -170,7 +190,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}.build()
)
dataSet.callback(this)
- centerMapOnLocation(dataSet.location)
+ centerMapOnBounds(dataSet.bounds)
} ?: run {
Toast.makeText(this, "Unknown dataset: $label", Toast.LENGTH_SHORT).show()
}
@@ -179,6 +199,11 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
+ googleMap.setOnCameraIdleListener {
+ val cp = googleMap.cameraPosition
+ Log.i(TAG, "CAMERA_PARAMS: target=LatLng(${cp.target.latitude}, ${cp.target.longitude}), zoom=${cp.zoom}f, tilt=${cp.tilt}f, bearing=${cp.bearing}f")
+ }
+
val capabilities: MapCapabilities = map.mapCapabilities
println("Data-driven Styling is available: " + capabilities.isDataDrivenStylingAvailable)
@@ -197,7 +222,7 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
val largePointRadius = 8F
val smallPointRadius = 6F
- val darkRedBrown = resources.getColor(R.color.darkRedBrown)
+ val darkRedBrown = ContextCompat.getColor(this, R.color.darkRedBrown)
val styleFactory = FeatureLayer.StyleFactory { feature: Feature ->
if (feature is DatasetFeature) {
@@ -337,8 +362,8 @@ class DataDrivenDatasetStylingActivity : SamplesBaseActivity(), OnMapReadyCallba
}
- private fun centerMapOnLocation(location: LatLng) {
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, zoomLevel))
+ private fun centerMapOnBounds(bounds: LatLngBounds, padding: Int = 80) {
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding))
}
// Define the click event handler to set lastGlobalId to globalid of selected feature.
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/EventsDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/EventsDemoActivity.kt
index 384eba27a..87a8a0dee 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/EventsDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/EventsDemoActivity.kt
@@ -17,6 +17,7 @@ import android.os.Bundle
import android.view.View
import android.widget.TextView
import com.example.common_ui.R
+import java.util.Locale
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.*
@@ -29,7 +30,7 @@ import com.google.android.gms.maps.model.LatLng
*/
// [START maps_android_sample_events]
class EventsDemoActivity : SamplesBaseActivity(), OnMapClickListener,
- OnMapLongClickListener, OnCameraIdleListener, OnMapReadyCallback {
+ OnMapLongClickListener, OnCameraIdleListener, OnCameraMoveListener, OnMapReadyCallback {
private lateinit var tapTextView: TextView
private lateinit var cameraTextView: TextView
@@ -42,28 +43,47 @@ class EventsDemoActivity : SamplesBaseActivity(), OnMapClickListener,
cameraTextView = findViewById(R.id.camera_text)
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(googleMap: GoogleMap) {
- // return early if the map was not initialised properly
map = googleMap
map.setOnMapClickListener(this)
map.setOnMapLongClickListener(this)
+ map.setOnCameraMoveListener(this)
map.setOnCameraIdleListener(this)
+ updateCameraPosition()
}
override fun onMapClick(point: LatLng) {
- tapTextView.text = "tapped, point=$point"
+ val lat = String.format(Locale.US, "%.6f", point.latitude)
+ val lng = String.format(Locale.US, "%.6f", point.longitude)
+ tapTextView.text = getString(R.string.events_tapped_format, lat, lng)
}
override fun onMapLongClick(point: LatLng) {
- tapTextView.text = "long pressed, point=$point"
+ val lat = String.format(Locale.US, "%.6f", point.latitude)
+ val lng = String.format(Locale.US, "%.6f", point.longitude)
+ tapTextView.text = getString(R.string.events_long_pressed_format, lat, lng)
+ }
+
+ override fun onCameraMove() {
+ updateCameraPosition()
}
override fun onCameraIdle() {
+ updateCameraPosition()
+ }
+
+ private fun updateCameraPosition() {
if (!::map.isInitialized) return
- cameraTextView.text = map.cameraPosition.toString()
+ val pos = map.cameraPosition
+ val lat = String.format(Locale.US, "%.6f", pos.target.latitude)
+ val lng = String.format(Locale.US, "%.6f", pos.target.longitude)
+ val zoom = String.format(Locale.US, "%.1f", pos.zoom)
+ val tilt = String.format(Locale.US, "%.1f", pos.tilt)
+ val bearing = String.format(Locale.US, "%.1f", pos.bearing)
+ cameraTextView.text = getString(R.string.events_camera_position_format, lat, lng, zoom, tilt, bearing)
}
}
// [END maps_android_sample_events]
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
index 8a1e77734..a1e169e20 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/GroundOverlayDemoActivity.kt
@@ -29,6 +29,7 @@ import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.GroundOverlay
import com.google.android.gms.maps.model.GroundOverlayOptions
import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
/**
* This demo shows how to add a ground overlay to a map.
@@ -63,7 +64,7 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
setContentView(binding.root)
binding.transparencySeekBar.max = TRANSPARENCY_MAX
- binding.transparencySeekBar.progress = 0
+ binding.transparencySeekBar.progress = 25
// Set up programmatic click listeners for the buttons.
// This is a better practice than using the android:onClick XML attribute, as it keeps
@@ -90,10 +91,8 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
// Register a listener to respond to clicks on GroundOverlays.
map.setOnGroundOverlayClickListener(this)
- // Move the camera to the Newark area.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11f))
-
- map.moveCamera(CameraUpdateFactory.scrollBy(100f, 100f))
+ // Move the camera to frame the Newark overlays with padding.
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(OVERLAY_BOUNDS, 80))
// Prepare the BitmapDescriptor objects. Using a BitmapDescriptorFactory is the most
// memory-efficient way to create the images that will be used for the overlays.
@@ -124,6 +123,7 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
GroundOverlayOptions()
.image(images[currentEntry]).anchor(0f, 1f)
.position(NEWARK, 8600f, 6500f)
+ .transparency(binding.transparencySeekBar.progress.toFloat() / TRANSPARENCY_MAX.toFloat())
) ?: error("Expected a non null addGroundOverlay")
groundOverlay.tag = images[currentEntry]
@@ -187,5 +187,9 @@ class GroundOverlayDemoActivity : SamplesBaseActivity(),
NEWARK.latitude - 0.001,
NEWARK.longitude - 0.025
)
+ internal val OVERLAY_BOUNDS = LatLngBounds(
+ LatLng(40.7050, -74.2600),
+ LatLng(40.7800, -74.1200)
+ )
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LayersDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LayersDemoActivity.kt
index 42167e088..2af972729 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LayersDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LayersDemoActivity.kt
@@ -28,6 +28,7 @@ import android.widget.CheckBox
import android.widget.Spinner
import com.example.common_ui.R
+import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.MAP_TYPE_HYBRID
import com.google.android.gms.maps.GoogleMap.MAP_TYPE_NONE
@@ -36,6 +37,8 @@ import com.google.android.gms.maps.GoogleMap.MAP_TYPE_SATELLITE
import com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.CameraPosition
+import com.google.android.gms.maps.model.LatLng
import pub.devrel.easypermissions.AfterPermissionGranted
import pub.devrel.easypermissions.EasyPermissions
@@ -106,6 +109,13 @@ class LayersDemoActivity :
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
+ val initialPosition = CameraPosition.builder()
+ .target(LatLng(-33.8688, 151.2093))
+ .zoom(16.5f)
+ .tilt(40.0f)
+ .build()
+ map.moveCamera(CameraUpdateFactory.newCameraPosition(initialPosition))
+
updateMapType()
// check the state of all checkboxes and update the map accordingly
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt
index 717b709b0..1789085a6 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt
@@ -54,21 +54,13 @@ class LiteListDemoActivity : SamplesBaseActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var mapAdapter: RecyclerView.Adapter
- /**
- * RecycleListener that completely clears the [com.google.android.gms.maps.GoogleMap]
- * attached to a row in the RecyclerView.
- * Sets the map type to [com.google.android.gms.maps.GoogleMap.MAP_TYPE_NONE] and clears
- * the map.
- */
- private val recycleListener = RecyclerView.RecyclerListener { holder ->
- val mapHolder = holder as MapAdapter.ViewHolder
- mapHolder.clearView()
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(com.example.common_ui.R.layout.lite_list_demo)
+ val toolbar = findViewById(com.example.common_ui.R.id.top_bar)
+ setSupportActionBar(toolbar)
+
mapAdapter = MapAdapter()
// Initialise the RecyclerView.
@@ -76,14 +68,13 @@ class LiteListDemoActivity : SamplesBaseActivity() {
setHasFixedSize(true)
layoutManager = linearLayoutManager
adapter = mapAdapter
- setRecyclerListener(recycleListener)
}
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
}
/** Create options menu to switch between the linear and grid layout managers. */
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
- menuInflater.inflate(R.menu.lite_list_menu, menu)
+ menuInflater.inflate(com.example.common_ui.R.menu.lite_list_menu, menu)
return true
}
@@ -91,7 +82,7 @@ class LiteListDemoActivity : SamplesBaseActivity() {
recyclerView.layoutManager = when (item.itemId) {
com.example.common_ui.R.id.layout_linear -> linearLayoutManager
com.example.common_ui.R.id.layout_grid -> gridLayoutManager
- else -> return false
+ else -> return super.onOptionsItemSelected(item)
}
return true
}
@@ -107,6 +98,11 @@ class LiteListDemoActivity : SamplesBaseActivity() {
holder.bindView(position)
}
+ override fun onViewRecycled(holder: ViewHolder) {
+ super.onViewRecycled(holder)
+ holder.clearView()
+ }
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflated = LayoutInflater.from(parent.context)
.inflate(com.example.common_ui.R.layout.lite_list_demo_row, parent, false)
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LocationSourceDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LocationSourceDemoActivity.kt
index 21fad59e8..d3bf48a8d 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LocationSourceDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/LocationSourceDemoActivity.kt
@@ -21,9 +21,8 @@ import android.os.Bundle
import android.view.View
import androidx.core.app.ActivityCompat
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.example.common_ui.R
import com.google.android.gms.maps.GoogleMap
@@ -34,6 +33,8 @@ import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.ktx.awaitMap
+import kotlinx.coroutines.launch
+
/**
* This shows how to use a custom location source.
*/
@@ -44,13 +45,14 @@ class LocationSourceDemoActivity : SamplesBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.basic_demo)
+ findViewById(R.id.top_bar)?.setTitle(R.string.location_source_demo_label)
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
- lifecycleScope.launchWhenCreated {
+ lifecycleScope.launch {
val map = mapFragment.awaitMap()
init(map = map)
}
lifecycle.addObserver(locationSource)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
@SuppressLint("MissingPermission")
@@ -72,7 +74,7 @@ class LocationSourceDemoActivity : SamplesBaseActivity() {
* at
* the point at which a user long pressed the map.
*/
-private class LongPressLocationSource : LocationSource, OnMapLongClickListener, LifecycleObserver {
+private class LongPressLocationSource : LocationSource, OnMapLongClickListener, DefaultLifecycleObserver {
private var listener: OnLocationChangedListener? = null
@@ -104,13 +106,11 @@ private class LongPressLocationSource : LocationSource, OnMapLongClickListener,
listener?.onLocationChanged(location)
}
- @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
- fun onPause() {
+ override fun onPause(owner: LifecycleOwner) {
paused = true
}
- @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
- fun onResume() {
+ override fun onResume(owner: LifecycleOwner) {
paused = false
}
}
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapColorSchemeActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapColorSchemeActivity.kt
index a2866b03e..dc8b4060e 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapColorSchemeActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapColorSchemeActivity.kt
@@ -46,7 +46,7 @@ class MapColorSchemeActivity :
buttonLight = findViewById(R.id.map_color_light_mode)
buttonDark = findViewById(R.id.map_color_dark_mode)
buttonFollowSystem = findViewById(R.id.map_color_follow_system_mode)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(googleMap: GoogleMap) {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapInPagerDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapInPagerDemoActivity.kt
index eff3890bf..5f54a3273 100755
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapInPagerDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MapInPagerDemoActivity.kt
@@ -42,7 +42,7 @@ class MapInPagerDemoActivity : SamplesBaseActivity() {
// This is required to avoid a black flash when the map is loaded. The flash is due
// to the use of a SurfaceView as the underlying view of the map.
pager.requestTransparentRegion(pager)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
/** A simple fragment that displays a TextView. */
@@ -55,6 +55,7 @@ class MapInPagerDemoActivity : SamplesBaseActivity() {
}
/** A simple FragmentPagerAdapter that returns two TextFragment and a SupportMapFragment. */
+ @Suppress("DEPRECATION")
class MyAdapter(fm: FragmentManager) :
FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerCloseInfoWindowOnRetapDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerCloseInfoWindowOnRetapDemoActivity.kt
index c9397e4e0..2a7726ec5 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerCloseInfoWindowOnRetapDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerCloseInfoWindowOnRetapDemoActivity.kt
@@ -70,7 +70,7 @@ class MarkerCloseInfoWindowOnRetapDemoActivity :
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
OnMapAndViewReadyListener(mapFragment, this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(googleMap: GoogleMap?) {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
index ce22a382e..1cb1fbd7e 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
@@ -22,6 +22,7 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
+import android.os.Looper
import android.os.SystemClock
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
@@ -36,7 +37,9 @@ import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
+import androidx.core.graphics.createBitmap
import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.graphics.toColorInt
import com.example.common_ui.R
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
@@ -290,7 +293,7 @@ class MarkerDemoActivity :
position = places.getValue("ALICE_SPRINGS"),
title = "Alice Springs",
icon = vectorToBitmap(
- R.drawable.ic_android, Color.parseColor("#A4C639"))
+ R.drawable.ic_android, "#A4C639".toColorInt())
),
// More markers for good measure
@@ -363,8 +366,11 @@ class MarkerDemoActivity :
Log.e(TAG, "Resource not found")
return BitmapDescriptorFactory.defaultMarker()
}
- val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth,
- vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
+ val bitmap = createBitmap(
+ vectorDrawable.intrinsicWidth,
+ vectorDrawable.intrinsicHeight,
+ Bitmap.Config.ARGB_8888
+ )
val canvas = Canvas(bitmap)
vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
DrawableCompat.setTint(vectorDrawable, color)
@@ -401,7 +407,7 @@ class MarkerDemoActivity :
if (marker.position == places.getValue("PERTH")) {
// This causes the marker at Perth to bounce into position when it is clicked.
- val handler = Handler()
+ val handler = Handler(Looper.getMainLooper())
val start = SystemClock.uptimeMillis()
val duration = 1500
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MultiMapDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MultiMapDemoActivity.kt
index 1ca406943..edaa1cb7b 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MultiMapDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MultiMapDemoActivity.kt
@@ -25,6 +25,6 @@ class MultiMapDemoActivity : SamplesBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.multimap_demo)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MyLocationDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MyLocationDemoActivity.kt
index e86d74bff..1a5c2eebc 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MyLocationDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/MyLocationDemoActivity.kt
@@ -56,7 +56,7 @@ class MyLocationDemoActivity : SamplesBaseActivity(),
val mapFragment =
supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
mapFragment?.getMapAsync(this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(googleMap: GoogleMap) {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
index 58f018c46..2d2118185 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
@@ -36,7 +36,7 @@ class OnMapAndViewReadyListener(
) : OnGlobalLayoutListener,
OnMapReadyCallback {
- private val mapView: View? = mapFragment.view
+ private var mapView: View? = null
private var isViewReady = false
private var isMapReady = false
@@ -52,16 +52,6 @@ class OnMapAndViewReadyListener(
}
private fun registerListeners() {
- // View layout.
- mapView?.let {
- if (it.width != 0 && it.height != 0) {
- // View has already completed layout.
- isViewReady = true
- } else {
- // Map has not undergone layout, register a View observer.
- it.viewTreeObserver.addOnGlobalLayoutListener(this)
- }
- }
// GoogleMap. Note if the GoogleMap is already ready it will still fire the callback later.
mapFragment.getMapAsync(this)
}
@@ -70,6 +60,22 @@ class OnMapAndViewReadyListener(
// NOTE: The GoogleMap API specifies the listener is removed just prior to invocation.
map = googleMap
isMapReady = true
+
+ // View layout.
+ mapView = mapFragment.view
+ val view = mapView
+ if (view != null) {
+ if (view.width != 0 && view.height != 0) {
+ // View has already completed layout.
+ isViewReady = true
+ } else {
+ // Map has not undergone layout, register a View observer.
+ view.viewTreeObserver.addOnGlobalLayoutListener(this)
+ }
+ } else {
+ isViewReady = true
+ }
+
fireCallbackIfReady()
}
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolygonDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolygonDemoActivity.kt
index fea47f8b7..e0d2e89c0 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolygonDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolygonDemoActivity.kt
@@ -131,7 +131,7 @@ class PolygonDemoActivity :
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
// [START_EXCLUDE silent]
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolylineDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolylineDemoActivity.kt
index a871551ea..1e695bf4e 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolylineDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/PolylineDemoActivity.kt
@@ -155,7 +155,7 @@ class PolylineDemoActivity :
val mapFragment = supportFragmentManager.findFragmentById(com.example.common_ui.R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
}
// [START_EXCLUDE silent]
@@ -165,8 +165,6 @@ class PolylineDemoActivity :
// [END_EXCLUDE]
override fun onMapReady(googleMap: GoogleMap) {
- googleMap
-
with(googleMap) {
// Override the default content description on the view, for accessibility mode.
setContentDescription(getString(com.example.common_ui.R.string.polyline_demo_description))
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/ProgrammaticDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/ProgrammaticDemoActivity.kt
index b54d13098..c9137f0dd 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/ProgrammaticDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/ProgrammaticDemoActivity.kt
@@ -13,7 +13,6 @@
// limitations under the License.
package com.example.kotlindemos
-import android.R
import android.os.Bundle
import android.view.View
import androidx.lifecycle.lifecycleScope
@@ -21,6 +20,7 @@ import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.ktx.addMarker
import com.google.maps.android.ktx.awaitMap
+import kotlinx.coroutines.launch
/**
* Demonstrates how to instantiate a SupportMapFragment programmatically and add a marker to it.
@@ -36,18 +36,18 @@ class ProgrammaticDemoActivity : SamplesBaseActivity() {
?: SupportMapFragment.newInstance().also {
// Then we add it using a FragmentTransaction.
val fragmentTransaction = supportFragmentManager.beginTransaction()
- fragmentTransaction.add(R.id.content, it, MAP_FRAGMENT_TAG)
+ fragmentTransaction.add(android.R.id.content, it, MAP_FRAGMENT_TAG)
fragmentTransaction.commit()
}
- lifecycleScope.launchWhenCreated {
+ lifecycleScope.launch {
val map = mapFragment.awaitMap()
map.addMarker {
position(LatLng(0.0, 0.0))
title("Marker")
}
}
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
}
companion object {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/RetainMapDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/RetainMapDemoActivity.kt
index 36c22497f..640bfb638 100755
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/RetainMapDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/RetainMapDemoActivity.kt
@@ -21,6 +21,7 @@ import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.ktx.addMarker
import com.google.maps.android.ktx.awaitMap
+import kotlinx.coroutines.launch
/**
* This shows how to retain a map across activity restarts (e.g., from screen rotations), which can
@@ -34,15 +35,16 @@ class RetainMapDemoActivity : SamplesBaseActivity() {
supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
if (savedInstanceState == null) {
// First incarnation of this activity.
+ @Suppress("DEPRECATION")
mapFragment.retainInstance = true
}
- lifecycleScope.launchWhenCreated {
+ lifecycleScope.launch {
val map = mapFragment.awaitMap()
map.addMarker {
position(LatLng(0.0, 0.0))
title("Marker")
}
}
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SamplesBaseActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SamplesBaseActivity.kt
index a6982e167..72f49c023 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SamplesBaseActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SamplesBaseActivity.kt
@@ -15,9 +15,9 @@ package com.example.kotlindemos
import android.os.Bundle
import android.view.View
+import android.view.ViewGroup
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
@@ -27,27 +27,81 @@ open class SamplesBaseActivity : AppCompatActivity() {
enableEdgeToEdge()
}
+ override fun setContentView(layoutResID: Int) {
+ super.setContentView(layoutResID)
+ setupEdgeToEdgeInsets()
+ }
+
+ override fun setContentView(view: View?) {
+ super.setContentView(view)
+ setupEdgeToEdgeInsets()
+ }
+
+ override fun setContentView(view: View?, params: ViewGroup.LayoutParams?) {
+ super.setContentView(view, params)
+ setupEdgeToEdgeInsets()
+ }
+
+ override fun addContentView(view: View?, params: ViewGroup.LayoutParams?) {
+ super.addContentView(view, params)
+ setupEdgeToEdgeInsets()
+ }
+
+ private fun setupEdgeToEdgeInsets() {
+ val root = findViewById(android.R.id.content) ?: return
+ val topBar = root.findViewById(com.example.common_ui.R.id.top_bar)
+ if (topBar != null) {
+ val typedValue = android.util.TypedValue()
+ val baseHeight = if (theme.resolveAttribute(android.R.attr.actionBarSize, typedValue, true)) {
+ android.util.TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics)
+ } else {
+ (56 * resources.displayMetrics.density).toInt()
+ }
+ ViewCompat.setOnApplyWindowInsetsListener(topBar) { view, insets ->
+ val statusBar = insets.getInsets(
+ WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout()
+ )
+ view.setPadding(
+ statusBar.left,
+ statusBar.top,
+ statusBar.right,
+ 0
+ )
+ view.layoutParams.height = baseHeight + statusBar.top
+ view.requestLayout()
+ insets
+ }
+ }
+
+ val mapContainer = root.findViewById(com.example.common_ui.R.id.map_container)
+ val bottomTarget = mapContainer ?: root
+ ViewCompat.setOnApplyWindowInsetsListener(bottomTarget) { view, insets ->
+ val navBars = insets.getInsets(
+ WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout()
+ )
+ val topInsets = if (topBar == null) {
+ insets.getInsets(WindowInsetsCompat.Type.statusBars()).top
+ } else {
+ 0
+ }
+ view.setPadding(
+ navBars.left,
+ topInsets,
+ navBars.right,
+ navBars.bottom
+ )
+ insets
+ }
+ }
+
companion object {
/**
* Applies insets to the container view to properly handle window insets.
*
* @param container the container view to apply insets to
*/
- fun applyInsets(container: View) {
- ViewCompat.setOnApplyWindowInsetsListener(
- container,
- OnApplyWindowInsetsListener { view: View?, insets: WindowInsetsCompat? ->
- val innerPadding =
- insets!!.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
- view!!.setPadding(
- innerPadding.left,
- innerPadding.top,
- innerPadding.right,
- innerPadding.bottom
- )
- insets
- }
- )
+ fun applyInsets(container: View? = null) {
+ // Handled automatically in SamplesBaseActivity
}
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SaveStateDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SaveStateDemoActivity.kt
index 07cbd9110..3acf93ad3 100755
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SaveStateDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SaveStateDemoActivity.kt
@@ -16,6 +16,7 @@ package com.example.kotlindemos
import android.os.Bundle
import android.os.Parcelable
+import androidx.core.os.BundleCompat
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener
@@ -26,7 +27,8 @@ import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.maps.android.ktx.addMarker
import com.google.maps.android.ktx.awaitMap
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
+import kotlinx.coroutines.launch
import java.util.Random
/**
@@ -73,13 +75,15 @@ class SaveStateDemoActivity : SamplesBaseActivity() {
// the savedInsanceState Bundle.
// - Custom Parcelable objects were wrapped in another Bundle.
mMarkerPosition =
- savedInstanceState?.getParcelable(MARKER_POSITION) ?: DEFAULT_MARKER_POSITION
+ savedInstanceState?.let { BundleCompat.getParcelable(it, MARKER_POSITION, LatLng::class.java) }
+ ?: DEFAULT_MARKER_POSITION
mMarkerInfo =
- savedInstanceState?.getBundle(OTHER_OPTIONS)?.getParcelable(MARKER_INFO) ?: MarkerInfo(
- BitmapDescriptorFactory.HUE_RED)
+ savedInstanceState?.getBundle(OTHER_OPTIONS)?.let {
+ BundleCompat.getParcelable(it, MARKER_INFO, MarkerInfo::class.java)
+ } ?: MarkerInfo(BitmapDescriptorFactory.HUE_RED)
mMoveCameraToMarker = savedInstanceState == null
- lifecycleScope.launchWhenCreated {
+ lifecycleScope.launch {
val map = awaitMap()
map.addMarker {
icon(BitmapDescriptorFactory.defaultMarker(mMarkerInfo.hue))
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SnapshotDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SnapshotDemoActivity.kt
index a8b5a221e..e2cce79c3 100755
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SnapshotDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SnapshotDemoActivity.kt
@@ -20,18 +20,27 @@ import android.widget.ImageView
import androidx.lifecycle.lifecycleScope
import com.example.common_ui.R
+import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.SnapshotReadyCallback
import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.ktx.awaitMap
+import kotlinx.coroutines.launch
/**
- * This shows how to take a snapshot of the map.
+ * Demonstrates capturing a bitmap screenshot of a [GoogleMap] view using [GoogleMap.snapshot].
+ *
+ * Key Concepts:
+ * 1. **Live Map Capture**: [GoogleMap.snapshot] takes an asynchronous render of the current
+ * map viewport and delivers it as an Android [android.graphics.Bitmap] via [SnapshotReadyCallback].
+ * 2. **Tile Readiness Synchronization**: If the "Wait for Map Load" option is selected,
+ * [GoogleMap.setOnMapLoadedCallback] is invoked first to ensure all vector tiles, labels,
+ * and overlays are fully rendered before capturing the bitmap.
+ * 3. **Material 3 Split View**: Displays the interactive map in a top card and the captured
+ * preview in a bottom card with empty-state placeholder handling.
*/
class SnapshotDemoActivity : SamplesBaseActivity() {
- /**
- * Note that this may be null if the Google Play services APK is not available.
- */
private lateinit var map: GoogleMap
private lateinit var binding: com.example.common_ui.databinding.SnapshotDemoBinding
@@ -40,32 +49,51 @@ class SnapshotDemoActivity : SamplesBaseActivity() {
binding = com.example.common_ui.databinding.SnapshotDemoBinding.inflate(layoutInflater)
setContentView(binding.root)
- binding.screenshotButton?.setOnClickListener { takeSnapshot() }
- binding.clearButton?.setOnClickListener { clearSnapshot() }
+ binding.screenshotButton.setOnClickListener { takeSnapshot() }
+ binding.clearButton.setOnClickListener { clearSnapshot() }
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
- lifecycleScope.launchWhenCreated {
+ lifecycleScope.launch {
map = mapFragment.awaitMap()
+ // Center on Venice, Italy — a visually rich standard vector map showing the Grand Canal and Rialto
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(VENICE, 14.5f))
}
applyInsets(binding.mapContainer)
}
+ /**
+ * Captures a snapshot of the current map viewport.
+ */
private fun takeSnapshot() {
- val callback =
- SnapshotReadyCallback { snapshot -> // Callback is called from the main thread, so we can modify the ImageView safely.
- binding.snapshotHolder.setImageBitmap(snapshot)
- }
- if ((binding.waitForMapLoad as CheckBox).isChecked) {
+ if (!::map.isInitialized) return
+
+ val callback = SnapshotReadyCallback { snapshot ->
+ // Callback runs on the main UI thread, so we can update the ImageView and card state directly.
+ binding.snapshotHolder.setImageBitmap(snapshot)
+ binding.snapshotPlaceholder.visibility = View.GONE
+ binding.snapshotLabel.visibility = View.VISIBLE
+ }
+
+ if (binding.waitForMapLoad.isChecked) {
+ // Wait until all map tiles are rendered before taking the snapshot
map.setOnMapLoadedCallback { map.snapshot(callback) }
} else {
+ // Take snapshot immediately with currently loaded tiles
map.snapshot(callback)
}
}
/**
- * Called when the clear button is clicked.
+ * Clears the captured snapshot image and restores the empty-state placeholder.
*/
private fun clearSnapshot() {
binding.snapshotHolder.setImageDrawable(null)
+ binding.snapshotPlaceholder.visibility = View.VISIBLE
+ binding.snapshotLabel.visibility = View.GONE
+ }
+
+ companion object {
+ // Venice, Italy (Grand Canal & Rialto)
+ internal val VENICE = LatLng(45.4380, 12.3350)
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SplitStreetViewPanoramaAndMapDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SplitStreetViewPanoramaAndMapDemoActivity.kt
index bc653c8d7..fb4401ee1 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SplitStreetViewPanoramaAndMapDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/SplitStreetViewPanoramaAndMapDemoActivity.kt
@@ -13,30 +13,67 @@
// limitations under the License.
package com.example.kotlindemos
+import android.Manifest
+import android.annotation.SuppressLint
+import android.content.pm.PackageManager
+import android.location.Location
import android.os.Bundle
-import android.view.View
+import android.widget.Toast
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.os.BundleCompat
import com.example.common_ui.R
-
+import com.google.android.gms.location.FusedLocationProviderClient
+import com.google.android.gms.location.LocationServices
+import com.google.android.gms.location.Priority
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener
import com.google.android.gms.maps.StreetViewPanorama
import com.google.android.gms.maps.StreetViewPanorama.OnStreetViewPanoramaChangeListener
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.SupportStreetViewPanoramaFragment
-import com.google.android.gms.maps.model.*
+import com.google.android.gms.maps.model.BitmapDescriptorFactory
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.Marker
+import com.google.android.gms.maps.model.MarkerOptions
+import com.google.android.gms.maps.model.StreetViewPanoramaLocation
+import com.google.android.gms.tasks.CancellationTokenSource
+import com.google.android.material.floatingactionbutton.FloatingActionButton
/**
- * This shows how to create a simple activity with streetview and a map
+ * Demonstrates bidirectional synchronization between a [SupportStreetViewPanoramaFragment]
+ * (top pane) and a [SupportMapFragment] (bottom pane).
+ *
+ * Key concepts illustrated:
+ * 1. **Map-to-Street View Sync**: Long-pressing and dragging the yellow "Pegman" marker on the map
+ * updates the Street View panorama to match the new drop coordinates.
+ * 2. **Street View-to-Map Sync**: Navigating within Street View (tapping forward arrows/chevrons)
+ * updates Pegman's position on the map and smoothly pans the map camera to follow.
+ * 3. **High-Accuracy Location**: Uses [FusedLocationProviderClient] with [Priority.PRIORITY_HIGH_ACCURACY]
+ * to teleport Pegman and Street View to the user's real-time physical location on demand.
*/
class SplitStreetViewPanoramaAndMapDemoActivity : SamplesBaseActivity(),
- OnMarkerDragListener, OnStreetViewPanoramaChangeListener {
- var streetViewPanorama: StreetViewPanorama? = null
- var marker: Marker? = null
+ OnMarkerDragListener, OnStreetViewPanoramaChangeListener,
+ ActivityCompat.OnRequestPermissionsResultCallback {
+
+ private var streetViewPanorama: StreetViewPanorama? = null
+ private var map: GoogleMap? = null
+ private var marker: Marker? = null
+ private lateinit var fusedLocationClient: FusedLocationProviderClient
+ private var cancellationTokenSource: CancellationTokenSource? = null
+ private var permissionRequested = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.split_street_view_panorama_and_map_demo)
- val markerPosition = savedInstanceState?.getParcelable(MARKER_POSITION_KEY) ?: SYDNEY
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
+ val markerPosition =
+ savedInstanceState?.let { BundleCompat.getParcelable(it, MARKER_POSITION_KEY, LatLng::class.java) }
+ ?: SYDNEY
+
+ // Initialize the Street View fragment (top pane)
val streetViewPanoramaFragment =
supportFragmentManager.findFragmentById(R.id.streetviewpanorama) as SupportStreetViewPanoramaFragment?
streetViewPanoramaFragment?.getStreetViewPanoramaAsync { panorama ->
@@ -44,23 +81,160 @@ class SplitStreetViewPanoramaAndMapDemoActivity : SamplesBaseActivity(),
streetViewPanorama?.setOnStreetViewPanoramaChangeListener(
this@SplitStreetViewPanoramaAndMapDemoActivity
)
- // Only need to set the position once as the streetview fragment will maintain
- // its state.
+ // Street View maintains its own state across orientation changes; only set position initially.
savedInstanceState ?: streetViewPanorama?.setPosition(SYDNEY)
}
+
+ // Initialize the Google Map fragment (bottom pane)
val mapFragment =
supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
- mapFragment?.getMapAsync { map ->
- map.setOnMarkerDragListener(this@SplitStreetViewPanoramaAndMapDemoActivity)
- // Creates a draggable marker. Long press to drag.
- marker = map.addMarker(
+ mapFragment?.getMapAsync { googleMap ->
+ map = googleMap
+ // Center map camera on Pegman's location with street-level zoom
+ googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerPosition, 16f))
+ googleMap.setOnMarkerDragListener(this@SplitStreetViewPanoramaAndMapDemoActivity)
+
+ // Hide the default top-right map button in favor of the unified Material FAB
+ googleMap.uiSettings.isMyLocationButtonEnabled = false
+ if (hasLocationPermission()) {
+ @SuppressLint("MissingPermission")
+ googleMap.isMyLocationEnabled = true
+ }
+
+ // Create a draggable Pegman marker on the map
+ marker = googleMap.addMarker(
MarkerOptions()
.position(markerPosition)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.pegman))
.draggable(true)
)
}
- applyInsets(findViewById(R.id.map_container))
+
+ // Material FAB to locate the user and jump Pegman to their neighborhood
+ findViewById(R.id.btn_my_location)?.setOnClickListener {
+ moveToMyLocation()
+ }
+ applyInsets(findViewById(R.id.map_container))
+ }
+
+ /**
+ * Checks if fine or coarse location permission is granted.
+ */
+ private fun hasLocationPermission(): Boolean {
+ return ContextCompat.checkSelfPermission(
+ this, Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
+ this, Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+
+ /**
+ * Requests high-accuracy live location via [FusedLocationProviderClient] and teleports
+ * Pegman, the map camera, and Street View to the user's location.
+ */
+ @SuppressLint("MissingPermission")
+ private fun moveToMyLocation() {
+ if (!hasLocationPermission()) {
+ if (permissionRequested && !ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION
+ ) && !ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ ) {
+ // Permanently denied ("Don't ask again") -> show informative toast guidance
+ Toast.makeText(
+ this,
+ R.string.location_permission_required_toast,
+ Toast.LENGTH_LONG
+ ).show()
+ } else {
+ permissionRequested = true
+ PermissionUtils.requestLocationPermissions(this, LOCATION_PERMISSION_REQUEST_CODE, false)
+ }
+ return
+ }
+
+ map?.isMyLocationEnabled = true
+ Toast.makeText(this, getString(R.string.getting_location), Toast.LENGTH_SHORT).show()
+
+ // Cancel any pending active location request
+ cancellationTokenSource?.cancel()
+ val cts = CancellationTokenSource()
+ cancellationTokenSource = cts
+
+ // Actively query NLP / GNSS for the current high-accuracy position
+ fusedLocationClient.getCurrentLocation(
+ Priority.PRIORITY_HIGH_ACCURACY,
+ cts.token
+ ).addOnSuccessListener { location: Location? ->
+ if (location != null) {
+ updatePositionToLocation(location)
+ } else {
+ // Fallback to last known cached location if live fix is temporarily unavailable
+ fusedLocationClient.lastLocation.addOnSuccessListener { fallbackLocation: Location? ->
+ if (fallbackLocation != null) {
+ updatePositionToLocation(fallbackLocation)
+ } else {
+ Toast.makeText(this, getString(R.string.waiting_for_location), Toast.LENGTH_SHORT).show()
+ }
+ }.addOnFailureListener {
+ Toast.makeText(this, getString(R.string.waiting_for_location), Toast.LENGTH_SHORT).show()
+ }
+ }
+ }.addOnFailureListener {
+ Toast.makeText(this, getString(R.string.waiting_for_location), Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ /**
+ * Updates Pegman's position, centers the map camera, and looks up the closest
+ * Street View panorama within a 200m radius of the user coordinates.
+ */
+ private fun updatePositionToLocation(location: Location) {
+ val userLatLng = LatLng(location.latitude, location.longitude)
+ marker?.position = userLatLng
+ map?.animateCamera(CameraUpdateFactory.newLatLngZoom(userLatLng, 16f))
+ streetViewPanorama?.setPosition(userLatLng, 200)
+ Toast.makeText(this, getString(R.string.moved_pegman_to_location), Toast.LENGTH_SHORT).show()
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ return
+ }
+ if (PermissionUtils.isPermissionGranted(
+ permissions,
+ grantResults,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) || PermissionUtils.isPermissionGranted(
+ permissions,
+ grantResults,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ ) {
+ moveToMyLocation()
+ } else {
+ if (!ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ ) {
+ Toast.makeText(
+ this,
+ R.string.location_permission_required_toast,
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ cancellationTokenSource?.cancel()
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -71,21 +245,37 @@ class SplitStreetViewPanoramaAndMapDemoActivity : SamplesBaseActivity(),
)
}
+ // --- Street View -> Map Synchronization ---
+
+ /**
+ * Called when the user navigates within the Street View panorama (e.g. stepping down a road).
+ * Synchronizes Pegman's position on the map and smoothly pans the camera.
+ */
override fun onStreetViewPanoramaChange(location: StreetViewPanoramaLocation) {
marker?.position = location.position
+ map?.animateCamera(CameraUpdateFactory.newLatLng(location.position))
}
+ // --- Map -> Street View Synchronization ---
+
override fun onMarkerDragStart(marker: Marker) {}
+
+ /**
+ * Called when the user finishes dragging Pegman on the map.
+ * Snaps the Street View panorama to the new drop location within a 150m search radius.
+ */
override fun onMarkerDragEnd(marker: Marker) {
streetViewPanorama?.setPosition(marker.position, 150)
+ map?.animateCamera(CameraUpdateFactory.newLatLng(marker.position))
}
override fun onMarkerDrag(marker: Marker) {}
companion object {
+ private const val LOCATION_PERMISSION_REQUEST_CODE = 1
private const val MARKER_POSITION_KEY = "MarkerPosition"
- // George St, Sydney
+ // Default start location: George St, Sydney, Australia
private val SYDNEY = LatLng(-33.87365, 151.20689)
}
}
\ No newline at end of file
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaBasicDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaBasicDemoActivity.kt
index 40ea537b1..94625ea75 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaBasicDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaBasicDemoActivity.kt
@@ -36,7 +36,7 @@ class StreetViewPanoramaBasicDemoActivity : SamplesBaseActivity() {
// loaded which is when the savedInstanceState is null).
savedInstanceState ?: panorama.setPosition(SYDNEY)
}
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
companion object {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaEventsDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaEventsDemoActivity.kt
index 1930d9fa7..4e08196b4 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaEventsDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaEventsDemoActivity.kt
@@ -74,22 +74,22 @@ class StreetViewPanoramaEventsDemoActivity : SamplesBaseActivity(),
// loaded which is when the savedInstanceState is null).
savedInstanceState ?: streetViewPanorama.setPosition(SYDNEY)
}
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onStreetViewPanoramaChange(location: StreetViewPanoramaLocation) {
- panoChangeTimesTextView.text = "Times panorama changed=" + ++panoChangeTimes
+ panoChangeTimesTextView.text = getString(R.string.pano_change_times, ++panoChangeTimes)
}
override fun onStreetViewPanoramaCameraChange(camera: StreetViewPanoramaCamera) {
- panoCameraChangeTextView.text = "Times camera changed=" + ++panoCameraChangeTimes
+ panoCameraChangeTextView.text = getString(R.string.pano_camera_change_times, ++panoCameraChangeTimes)
}
override fun onStreetViewPanoramaClick(orientation: StreetViewPanoramaOrientation) {
val point = streetViewPanorama.orientationToPoint(orientation)
point?.let {
panoClickTimes++
- panoClickTextView.text = "Times clicked=$panoClickTimes : $point"
+ panoClickTextView.text = getString(R.string.pano_click_times, panoClickTimes, it)
streetViewPanorama.animateTo(
StreetViewPanoramaCamera.Builder()
.orientation(orientation)
@@ -103,7 +103,7 @@ class StreetViewPanoramaEventsDemoActivity : SamplesBaseActivity(),
val point = streetViewPanorama.orientationToPoint(orientation)
if (point != null) {
panoLongClickTimes++
- panoLongClickTextView.text = "Times long clicked=$panoLongClickTimes : $point"
+ panoLongClickTextView.text = getString(R.string.pano_long_click_times, panoLongClickTimes, point)
}
}
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt
index e06169426..2101014ee 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt
@@ -190,7 +190,7 @@ class StreetViewPanoramaNavigationDemoActivity : SamplesBaseActivity() {
private fun onMovePosition() {
val location = streetViewPanorama.location
val camera = streetViewPanorama.panoramaCamera
- location.links?.let {
+ if (location.links.isNotEmpty()) {
val link = location.links.findClosestLinkToBearing(camera.bearing)
streetViewPanorama.setPosition(link.panoId)
}
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaViewDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaViewDemoActivity.kt
index 296844220..2b81f5215 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaViewDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StreetViewPanoramaViewDemoActivity.kt
@@ -45,7 +45,7 @@ class StreetViewPanoramaViewDemoActivity : SamplesBaseActivity() {
// StreetViewPanoramaView requires that the Bundle you pass contain _ONLY_
// StreetViewPanoramaView SDK objects or sub-Bundles.
streetViewPanoramaView.onCreate(savedInstanceState?.getBundle(STREETVIEW_BUNDLE_KEY))
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onResume() {
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StyledMapDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StyledMapDemoActivity.kt
index 7df53b8fc..2ec877022 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StyledMapDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/StyledMapDemoActivity.kt
@@ -1,148 +1,148 @@
-/*
- * Copyright 2023 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.
- */
-
-package com.example.kotlindemos
-
-import android.content.DialogInterface
-import android.os.Bundle
-import android.util.Log
-import android.view.Menu
-import android.view.MenuItem
-import android.view.View
-import android.widget.Toast
-import androidx.appcompat.app.AlertDialog
-
-import com.google.android.gms.maps.CameraUpdateFactory
-import com.google.android.gms.maps.GoogleMap
-import com.google.android.gms.maps.OnMapReadyCallback
-import com.google.android.gms.maps.SupportMapFragment
-import com.google.android.gms.maps.model.LatLng
-import com.google.android.gms.maps.model.MapStyleOptions
-import java.util.ArrayList
-
-class StyledMapDemoActivity : SamplesBaseActivity(), OnMapReadyCallback {
-
- private var mMap: GoogleMap? = null
- private var mSelectedStyleId = com.example.common_ui.R.string.style_label_default
-
- companion object {
- private const val TAG = "StyledMapDemoActivity"
- private const val SELECTED_STYLE = "selected_style"
- private val SYDNEY = LatLng(-33.8688, 151.2093)
- }
-
- private val mStyleIds = intArrayOf(
- com.example.common_ui.R.string.style_label_retro,
- com.example.common_ui.R.string.style_label_night,
- com.example.common_ui.R.string.style_label_grayscale,
- com.example.common_ui.R.string.style_label_no_pois_no_transit,
- com.example.common_ui.R.string.style_label_default
- )
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- if (savedInstanceState != null) {
- mSelectedStyleId = savedInstanceState.getInt(SELECTED_STYLE)
- }
- setContentView(com.example.common_ui.R.layout.styled_map_demo)
-
- val mapFragment =
- supportFragmentManager.findFragmentById(com.example.common_ui.R.id.map) as SupportMapFragment
- mapFragment.getMapAsync(this)
- applyInsets(findViewById(com.example.common_ui.R.id.map_container))
- }
-
- override fun onSaveInstanceState(outState: Bundle) {
- outState.putInt(SELECTED_STYLE, mSelectedStyleId)
- super.onSaveInstanceState(outState)
- }
-
- override fun onMapReady(map: GoogleMap) {
- mMap = map
- mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 14f))
- setSelectedStyle()
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.styled_map, menu)
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- if (item.itemId == com.example.common_ui.R.id.menu_style_choose) {
- showStylesDialog()
- }
- return true
- }
-
- private fun showStylesDialog() {
- val styleNames = ArrayList()
- for (style in mStyleIds) {
- styleNames.add(getString(style))
- }
-
- val builder = AlertDialog.Builder(this)
- builder.setTitle(getString(com.example.common_ui.R.string.style_choose))
- builder.setItems(styleNames.toTypedArray(),
- DialogInterface.OnClickListener { _, which ->
- mSelectedStyleId = mStyleIds[which]
- val msg = getString(com.example.common_ui.R.string.style_set_to, getString(mSelectedStyleId))
- Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
- Log.d(TAG, msg)
- setSelectedStyle()
- })
- builder.show()
- }
-
- private fun setSelectedStyle() {
- val style: MapStyleOptions?
- val id = mSelectedStyleId
- style = when (id) {
- com.example.common_ui.R.string.style_label_retro ->
- MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_retro)
- com.example.common_ui.R.string.style_label_night ->
- MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_night)
- com.example.common_ui.R.string.style_label_grayscale ->
- MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_grayscale)
- com.example.common_ui.R.string.style_label_no_pois_no_transit ->
- MapStyleOptions(
- "[" +
- " {" +
- " \"featureType\":\"poi.business\"," +
- " \"elementType\":\"all\"," +
- " \"stylers\":[" +
- " {" +
- " \"visibility\":\"off\"" +
- " }" +
- " ]" +
- " }," +
- " {" +
- " \"featureType\":\"transit\"," +
- " \"elementType\":\"all\"," +
- " \"stylers\":[" +
- " {" +
- " \"visibility\":\"off\"" +
- " }" +
- " ]" +
- " }" +
- "]"
- )
- com.example.common_ui.R.string.style_label_default -> null
- else -> return
- }
- mMap?.setMapStyle(style)
- }
-}
+/*
+ * Copyright 2023 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.
+ */
+
+package com.example.kotlindemos
+
+import android.content.DialogInterface
+import android.os.Bundle
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.MapStyleOptions
+import java.util.ArrayList
+
+class StyledMapDemoActivity : SamplesBaseActivity(), OnMapReadyCallback {
+
+ private var mMap: GoogleMap? = null
+ private var mSelectedStyleId = com.example.common_ui.R.string.style_label_default
+
+ companion object {
+ private const val TAG = "StyledMapDemoActivity"
+ private const val SELECTED_STYLE = "selected_style"
+ private val SYDNEY = LatLng(-33.8688, 151.2093)
+ }
+
+ private val mStyleIds = intArrayOf(
+ com.example.common_ui.R.string.style_label_retro,
+ com.example.common_ui.R.string.style_label_night,
+ com.example.common_ui.R.string.style_label_grayscale,
+ com.example.common_ui.R.string.style_label_no_pois_no_transit,
+ com.example.common_ui.R.string.style_label_default
+ )
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (savedInstanceState != null) {
+ mSelectedStyleId = savedInstanceState.getInt(SELECTED_STYLE)
+ }
+ setContentView(com.example.common_ui.R.layout.styled_map_demo)
+
+ val mapFragment =
+ supportFragmentManager.findFragmentById(com.example.common_ui.R.id.map) as SupportMapFragment
+ mapFragment.getMapAsync(this)
+ applyInsets(findViewById(com.example.common_ui.R.id.map_container))
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putInt(SELECTED_STYLE, mSelectedStyleId)
+ super.onSaveInstanceState(outState)
+ }
+
+ override fun onMapReady(map: GoogleMap) {
+ mMap = map
+ mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 14f))
+ setSelectedStyle()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.styled_map, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == com.example.common_ui.R.id.menu_style_choose) {
+ showStylesDialog()
+ }
+ return true
+ }
+
+ private fun showStylesDialog() {
+ val styleNames = ArrayList()
+ for (style in mStyleIds) {
+ styleNames.add(getString(style))
+ }
+
+ val builder = AlertDialog.Builder(this)
+ builder.setTitle(getString(com.example.common_ui.R.string.style_choose))
+ builder.setItems(styleNames.toTypedArray(),
+ DialogInterface.OnClickListener { _, which ->
+ mSelectedStyleId = mStyleIds[which]
+ val msg = getString(com.example.common_ui.R.string.style_set_to, getString(mSelectedStyleId))
+ Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
+ Log.d(TAG, msg)
+ setSelectedStyle()
+ })
+ builder.show()
+ }
+
+ private fun setSelectedStyle() {
+ val style: MapStyleOptions?
+ val id = mSelectedStyleId
+ style = when (id) {
+ com.example.common_ui.R.string.style_label_retro ->
+ MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_retro)
+ com.example.common_ui.R.string.style_label_night ->
+ MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_night)
+ com.example.common_ui.R.string.style_label_grayscale ->
+ MapStyleOptions.loadRawResourceStyle(this, com.example.common_ui.R.raw.mapstyle_grayscale)
+ com.example.common_ui.R.string.style_label_no_pois_no_transit ->
+ MapStyleOptions(
+ "[" +
+ " {" +
+ " \"featureType\":\"poi.business\"," +
+ " \"elementType\":\"all\"," +
+ " \"stylers\":[" +
+ " {" +
+ " \"visibility\":\"off\"" +
+ " }" +
+ " ]" +
+ " }," +
+ " {" +
+ " \"featureType\":\"transit\"," +
+ " \"elementType\":\"all\"," +
+ " \"stylers\":[" +
+ " {" +
+ " \"visibility\":\"off\"" +
+ " }" +
+ " ]" +
+ " }" +
+ "]"
+ )
+ com.example.common_ui.R.string.style_label_default -> null
+ else -> return
+ }
+ mMap?.setMapStyle(style)
+ }
+}
diff --git a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/TagsDemoActivity.kt b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/TagsDemoActivity.kt
index d282bc03f..48fefeb76 100644
--- a/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/TagsDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/main/java/com/example/kotlindemos/TagsDemoActivity.kt
@@ -88,7 +88,7 @@ class TagsDemoActivity : SamplesBaseActivity(),
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
OnMapAndViewReadyListener(mapFragment, this)
- applyInsets(findViewById(R.id.map_container))
+ applyInsets(findViewById(R.id.map_container))
}
override fun onMapReady(googleMap: GoogleMap?) {
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..5ac5b7060 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
@@ -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/main/res/layout/save_state_demo.xml b/ApiDemos/project/kotlin-app/src/main/res/layout/save_state_demo.xml
new file mode 100644
index 000000000..4291e256d
--- /dev/null
+++ b/ApiDemos/project/kotlin-app/src/main/res/layout/save_state_demo.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/MarkerDemoActivity.kt b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/MarkerDemoActivity.kt
index 19db8ca20..9a76aa79e 100644
--- a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/MarkerDemoActivity.kt
+++ b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/MarkerDemoActivity.kt
@@ -29,6 +29,7 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Handler
+import android.os.Looper
import android.os.SystemClock
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
@@ -46,7 +47,9 @@ import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
+import androidx.core.graphics.createBitmap
import androidx.core.graphics.drawable.DrawableCompat
+import androidx.core.graphics.toColorInt
import com.google.android.libraries.maps.CameraUpdateFactory
import com.google.android.libraries.maps.GoogleMap
import com.google.android.libraries.maps.GoogleMap.InfoWindowAdapter
@@ -299,7 +302,7 @@ class MarkerDemoActivity :
position = places.getValue("ALICE_SPRINGS"),
title = "Alice Springs",
icon = vectorToBitmap(
- com.example.common_ui.R.drawable.ic_android, Color.parseColor("#A4C639"))
+ com.example.common_ui.R.drawable.ic_android, "#A4C639".toColorInt())
),
// More markers for good measure
@@ -371,8 +374,11 @@ class MarkerDemoActivity :
Log.e(TAG, "Resource not found")
return BitmapDescriptorFactory.defaultMarker()
}
- val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth,
- vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
+ val bitmap = createBitmap(
+ vectorDrawable.intrinsicWidth,
+ vectorDrawable.intrinsicHeight,
+ Bitmap.Config.ARGB_8888
+ )
val canvas = Canvas(bitmap)
vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
DrawableCompat.setTint(vectorDrawable, color)
@@ -415,7 +421,7 @@ class MarkerDemoActivity :
if (marker.position == places.getValue("PERTH")) {
// This causes the marker at Perth to bounce into position when it is clicked.
- val handler = Handler()
+ val handler = Handler(Looper.getMainLooper())
val start = SystemClock.uptimeMillis()
val duration = 1500
diff --git a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
index decf452c9..4e92a013a 100644
--- a/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
+++ b/ApiDemos/project/kotlin-app/src/v3/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
@@ -43,7 +43,7 @@ class OnMapAndViewReadyListener(
) : OnGlobalLayoutListener,
OnMapReadyCallback {
- private val mapView: View? = mapFragment.view
+ private var mapView: View? = null
private var isViewReady = false
private var isMapReady = false
@@ -59,15 +59,6 @@ class OnMapAndViewReadyListener(
}
private fun registerListeners() {
- // View layout.
- if (mapView?.width != 0 && mapView?.height != 0) {
- // View has already completed layout.
- isViewReady = true
- } else {
- // Map has not undergone layout, register a View observer.
- mapView.viewTreeObserver.addOnGlobalLayoutListener(this)
- }
-
// GoogleMap. Note if the GoogleMap is already ready it will still fire the callback later.
mapFragment.getMapAsync(this)
}
@@ -76,6 +67,22 @@ class OnMapAndViewReadyListener(
// NOTE: The GoogleMap API specifies the listener is removed just prior to invocation.
map = googleMap ?: return
isMapReady = true
+
+ // View layout.
+ mapView = mapFragment.view
+ val view = mapView
+ if (view != null) {
+ if (view.width != 0 && view.height != 0) {
+ // View has already completed layout.
+ isViewReady = true
+ } else {
+ // Map has not undergone layout, register a View observer.
+ view.viewTreeObserver.addOnGlobalLayoutListener(this)
+ }
+ } else {
+ isViewReady = true
+ }
+
fireCallbackIfReady()
}
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..ef344871a 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
@@ -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
diff --git a/FireMarkers/app/src/main/java/com/example/firemarkers/MainActivity.kt b/FireMarkers/app/src/main/java/com/example/firemarkers/MainActivity.kt
index a970ef38a..ba6ce5dac 100644
--- a/FireMarkers/app/src/main/java/com/example/firemarkers/MainActivity.kt
+++ b/FireMarkers/app/src/main/java/com/example/firemarkers/MainActivity.kt
@@ -36,6 +36,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp
@@ -47,8 +48,8 @@ import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.Marker
-import com.google.maps.android.compose.MarkerState
import com.google.maps.android.compose.rememberCameraPositionState
+import com.google.maps.android.compose.rememberUpdatedMarkerState
import dagger.hilt.android.AndroidEntryPoint
import androidx.core.view.WindowCompat
@@ -149,13 +150,16 @@ fun MapScreen(modifier: Modifier = Modifier) {
cameraPositionState = cameraPositionState
) {
markers.forEach { markerData ->
- Marker(
- state = remember(markerData.id) {
- MarkerState(position = LatLng(markerData.latitude, markerData.longitude))
- },
- title = markerData.label,
- icon = BitmapDescriptorFactory.defaultMarker(markerData.color)
- )
+ key(markerData.id) {
+ val markerState = rememberUpdatedMarkerState(
+ position = LatLng(markerData.latitude, markerData.longitude)
+ )
+ Marker(
+ state = markerState,
+ title = markerData.label,
+ icon = BitmapDescriptorFactory.defaultMarker(markerData.color)
+ )
+ }
}
}
}
diff --git a/WearOS/Wearable/build.gradle.kts b/WearOS/Wearable/build.gradle.kts
index 7a6596fdb..b1e2f174b 100644
--- a/WearOS/Wearable/build.gradle.kts
+++ b/WearOS/Wearable/build.gradle.kts
@@ -45,8 +45,15 @@ android {
sarifOutput = layout.buildDirectory.file("reports/lint-results-debug.sarif").get().asFile
}
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
kotlin {
- jvmToolchain(21)
+ compilerOptions {
+ jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
+ }
}
}
@@ -90,11 +97,11 @@ dependencies {
// compileOnly("com.google.android.wearable:wearable:2.9.0")
// implementation("com.google.android.support:wearable:2.9.0")
// implementation("com.google.android.gms:play-services-maps:20.0.0")
- // implementation("androidx.wear:wear:1.3.0")
- // androidTestImplementation("androidx.test.ext:junit:1.1.5")
- // androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+ // implementation("androidx.wear:wear:1.4.0")
+ // androidTestImplementation("androidx.test.ext:junit:1.3.0")
+ // androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
// androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
- // androidTestImplementation("com.google.truth:truth:1.4.2")
+ // androidTestImplementation("com.google.truth:truth:1.4.5")
// androidTestImplementation("junit:junit:4.13.2")
}
// [END maps_wear_os_dependencies]
diff --git a/WearOS/Wearable/src/main/java/com/example/wearosmap/AmbientActivity.java b/WearOS/Wearable/src/main/java/com/example/wearosmap/AmbientActivity.java
index e20e969a3..1d3d4c0cc 100644
--- a/WearOS/Wearable/src/main/java/com/example/wearosmap/AmbientActivity.java
+++ b/WearOS/Wearable/src/main/java/com/example/wearosmap/AmbientActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * 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.
@@ -48,8 +48,12 @@ public void onCreate(Bundle savedState) {
// Enable ambient support, so the map remains visible in simplified, low-color display
// when the user is no longer actively using the app but the app is still visible on the
// watch face.
- AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
- Log.d(AmbientActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
+ try {
+ AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
+ Log.d(AmbientActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
+ } catch (Exception e) {
+ Log.w(AmbientActivity.class.getSimpleName(), "Ambient mode unavailable on this device: " + e.getMessage());
+ }
// Obtain the MapFragment and set the async listener to be notified when the map is ready.
mapFragment = (SupportMapFragment) getSupportFragmentManager()
diff --git a/WearOS/Wearable/src/main/java/com/example/wearosmap/MainActivity.java b/WearOS/Wearable/src/main/java/com/example/wearosmap/MainActivity.java
index 493292ee0..ebc9ce6da 100644
--- a/WearOS/Wearable/src/main/java/com/example/wearosmap/MainActivity.java
+++ b/WearOS/Wearable/src/main/java/com/example/wearosmap/MainActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * 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.
@@ -54,9 +54,13 @@ public void onCreate(Bundle savedState) {
// when the user is no longer actively using the app but the app is still visible on the
// watch face.
// [START maps_wear_os_ambient_mode_support]
- AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
+ try {
+ AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
+ Log.d(MainActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
+ } catch (Exception e) {
+ Log.w(MainActivity.class.getSimpleName(), "Ambient mode unavailable on this device: " + e.getMessage());
+ }
// [END maps_wear_os_ambient_mode_support]
- Log.d(MainActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
// Retrieve the containers for the root of the layout and the map. Margins will need to be
// set on them to account for the system window insets.
diff --git a/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/AmbientActivity.kt b/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/AmbientActivity.kt
index e14ebf473..9e600e161 100644
--- a/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/AmbientActivity.kt
+++ b/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/AmbientActivity.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * 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.
@@ -39,8 +39,12 @@ class AmbientActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackP
// Enable ambient support, so the map remains visible in simplified, low-color display
// when the user is no longer actively using the app but the app is still visible on the
// watch face.
- val controller = AmbientModeSupport.attach(this)
- Log.d(AmbientActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
+ try {
+ val controller = AmbientModeSupport.attach(this)
+ Log.d(AmbientActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
+ } catch (e: Exception) {
+ Log.w(AmbientActivity::class.java.simpleName, "Ambient mode unavailable on this device: ${e.message}")
+ }
// Obtain the MapFragment and set the async listener to be notified when the map is ready.
mapFragment = supportFragmentManager
diff --git a/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/MainActivity.kt b/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/MainActivity.kt
index b80e4a28d..c3b1ec8e8 100644
--- a/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/MainActivity.kt
+++ b/WearOS/Wearable/src/main/kotlin/com/example/wearosmap/kt/MainActivity.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
+ * 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.
@@ -49,9 +49,13 @@ class MainActivity : AppCompatActivity(), OnMapReadyCallback,
// when the user is no longer actively using the app but the app is still visible on the
// watch face.
// [START maps_wear_os_ambient_mode_support]
- val controller = AmbientModeSupport.attach(this)
+ try {
+ val controller = AmbientModeSupport.attach(this)
+ Log.d(MainActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
+ } catch (e: Exception) {
+ Log.w(MainActivity::class.java.simpleName, "Ambient mode unavailable on this device: ${e.message}")
+ }
// [END maps_wear_os_ambient_mode_support]
- Log.d(MainActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
// Retrieve the containers for the root of the layout and the map. Margins will need to be
// set on them to account for the system window insets.
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 189e0dc0c..0f2eeee37 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -40,6 +40,7 @@ mapsCompose = "8.4.0"
mapsKtx = "6.3.0"
mapsUtils = "5.1.1"
places = "5.3.0"
+playServicesLocation = "21.4.0"
playServicesMaps = "20.0.0"
secretsGradlePlugin = "2.0.1"
@@ -106,6 +107,7 @@ maps-ktx = { group = "com.google.maps.android", name = "maps-ktx", version.ref =
maps-utils = { module = "com.google.maps.android:android-maps-utils", version.ref = "mapsUtils" }
maps-utils-ktx = { group = "com.google.maps.android", name = "maps-utils-ktx", version.ref = "mapsKtx" }
places = { group = "com.google.android.libraries.places", name = "places", version.ref = "places" }
+play-services-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "playServicesLocation" }
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
# Wear OS
diff --git a/snippets/app-compose/build.gradle.kts b/snippets/app-compose/build.gradle.kts
index 129c8e19d..767871f02 100644
--- a/snippets/app-compose/build.gradle.kts
+++ b/snippets/app-compose/build.gradle.kts
@@ -36,6 +36,7 @@ android {
buildTypes {
release {
isMinifyEnabled = true
+ isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
diff --git a/snippets/app-ktx/build.gradle.kts b/snippets/app-ktx/build.gradle.kts
index e305a70b0..cef1dba45 100644
--- a/snippets/app-ktx/build.gradle.kts
+++ b/snippets/app-ktx/build.gradle.kts
@@ -42,6 +42,7 @@ android {
buildTypes {
release {
isMinifyEnabled = true
+ isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
diff --git a/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/KML.kt b/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/KML.kt
index bbc9e09cb..ea38c2e98 100644
--- a/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/KML.kt
+++ b/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/KML.kt
@@ -68,7 +68,7 @@ internal class KML {
// [START maps_android_utils_kml_access_properties]
for (container in layer.getContainers()) {
if (container.hasProperty("name")) {
- Log.i("KML", container.getProperty("name")!!)
+ Log.i("KML", container.getProperty("name") ?: "")
}
}
// [END maps_android_utils_kml_access_properties]
diff --git a/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/Multilayer.kt b/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/Multilayer.kt
index f87024baa..b54671865 100644
--- a/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/Multilayer.kt
+++ b/snippets/app-utils-ktx/src/main/java/com/example/app_utils_ktx/Multilayer.kt
@@ -35,26 +35,26 @@ import org.xmlpull.v1.XmlPullParserException
import java.io.IOException
internal class Multilayer {
- private val map: GoogleMap? = null
- private val context: Context? = null
+ private lateinit var map: GoogleMap
+ private lateinit var context: Context
@Suppress("IndexOutOfBoundsException")
@Throws(IOException::class, JSONException::class, XmlPullParserException::class)
private fun init() {
// [START maps_android_utils_multilayer_init]
val markerManager = MarkerManager(map)
- val groundOverlayManager = GroundOverlayManager(map!!)
+ val groundOverlayManager = GroundOverlayManager(map)
val polygonManager = PolygonManager(map)
val polylineManager = PolylineManager(map)
// [END maps_android_utils_multilayer_init]
// [START maps_android_utils_multilayer_manager]
val clusterManager =
- ClusterManager(context!!, map, markerManager)
+ ClusterManager(context, map, markerManager)
val geoJsonLineLayer = GeoJsonLayer(
map,
R.raw.geojson_file,
- context!!,
+ context,
markerManager,
polygonManager,
polylineManager,
@@ -63,7 +63,7 @@ internal class Multilayer {
val kmlPolylineLayer = KmlLayer(
map,
R.raw.kml_file,
- context!!,
+ context,
markerManager,
polygonManager,
polylineManager,
diff --git a/snippets/app/src/main/java/com/google/maps/example/TileOverlays.java b/snippets/app/src/main/java/com/google/maps/example/TileOverlays.java
index 82a19879d..ba34c28c2 100644
--- a/snippets/app/src/main/java/com/google/maps/example/TileOverlays.java
+++ b/snippets/app/src/main/java/com/google/maps/example/TileOverlays.java
@@ -23,6 +23,7 @@
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Locale;
class TileOverlays implements OnMapReadyCallback {
// [START maps_android_tile_overlays_add]
@@ -34,7 +35,7 @@ class TileOverlays implements OnMapReadyCallback {
public URL getTileUrl(int x, int y, int zoom) {
/* Define the URL pattern for the tile images */
- String s = String.format("http://my.image.server/images/%d/%d/%d.png", zoom, x, y);
+ String s = String.format(Locale.US, "http://my.image.server/images/%d/%d/%d.png", zoom, x, y);
if (!checkTileExists(x, y, zoom)) {
return null;
diff --git a/tutorials/java/Polygons/app/build.gradle.kts b/tutorials/java/Polygons/app/build.gradle.kts
index a8ec2ad89..191662b5d 100644
--- a/tutorials/java/Polygons/app/build.gradle.kts
+++ b/tutorials/java/Polygons/app/build.gradle.kts
@@ -28,7 +28,7 @@ android {
targetSdk = libs.versions.targetSdk.get().toInt()
versionCode = libs.versions.versionCode.get().toInt()
versionName = libs.versions.versionName.get()
- testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
diff --git a/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle.kts b/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle.kts
index a3bbb1b3f..21adef2c8 100644
--- a/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle.kts
+++ b/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/build.gradle.kts
@@ -73,7 +73,7 @@ dependencies {
testImplementation(libs.junit)
implementation(libs.coreKtx)
implementation(libs.lifecycleViewModelKtx)
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:${libs.versions.kotlin.get()}")
+ implementation(libs.kotlin.stdlib)
implementation(libs.material)
}
diff --git a/tutorials/kotlin/Polygons/app/build.gradle.kts b/tutorials/kotlin/Polygons/app/build.gradle.kts
index d326d26ff..97abaa764 100644
--- a/tutorials/kotlin/Polygons/app/build.gradle.kts
+++ b/tutorials/kotlin/Polygons/app/build.gradle.kts
@@ -30,7 +30,7 @@ android {
targetSdk = libs.versions.targetSdk.get().toInt()
versionCode = libs.versions.versionCode.get().toInt()
versionName = libs.versions.versionName.get()
- testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
diff --git a/tutorials/kotlin/Polygons/app/src/main/java/com/example/polygons/PolyActivity.kt b/tutorials/kotlin/Polygons/app/src/main/java/com/example/polygons/PolyActivity.kt
index 51f4389e3..e40685d8c 100644
--- a/tutorials/kotlin/Polygons/app/src/main/java/com/example/polygons/PolyActivity.kt
+++ b/tutorials/kotlin/Polygons/app/src/main/java/com/example/polygons/PolyActivity.kt
@@ -185,7 +185,7 @@ class PolyActivity : AppCompatActivity(), OnMapReadyCallback, OnPolylineClickLis
// The default pattern is a solid stroke.
polyline.pattern = null
}
- Toast.makeText(this, "Route type " + polyline.tag.toString(),
+ Toast.makeText(this, "Route type ${polyline.tag}",
Toast.LENGTH_SHORT).show()
}
// [END maps_poly_activity_on_polyline_click]