From 817c63e89756d4a140b9864a324fd71ddd9ee913 Mon Sep 17 00:00:00 2001 From: Mark Sohm Date: Tue, 23 Dec 2025 14:52:31 -0500 Subject: [PATCH] add multi floor view and stacked maps demos update readme --- .../app/src/main/AndroidManifest.xml | 8 + .../java/com/mappedin/demo/MainActivity.kt | 12 +- .../demo/MultiFloorViewDemoActivity.kt | 129 ++++++++++ .../mappedin/demo/StackedMapsDemoActivity.kt | 227 ++++++++++++++++++ .../com/mappedin/demo/StackedMapsUtils.kt | 211 ++++++++++++++++ readme.md | 11 +- 6 files changed, 590 insertions(+), 8 deletions(-) create mode 100644 SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MultiFloorViewDemoActivity.kt create mode 100644 SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsDemoActivity.kt create mode 100644 SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsUtils.kt diff --git a/SDKv6_Examples/PlaygroundSamples/app/src/main/AndroidManifest.xml b/SDKv6_Examples/PlaygroundSamples/app/src/main/AndroidManifest.xml index ca0bd15..940d700 100644 --- a/SDKv6_Examples/PlaygroundSamples/app/src/main/AndroidManifest.xml +++ b/SDKv6_Examples/PlaygroundSamples/app/src/main/AndroidManifest.xml @@ -47,6 +47,10 @@ android:name="com.mappedin.demo.ModelsDemoActivity" android:exported="false" android:theme="@style/Theme.Material3.DayNight.NoActionBar" /> + + diff --git a/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MainActivity.kt b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MainActivity.kt index f322593..373ca31 100644 --- a/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MainActivity.kt +++ b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MainActivity.kt @@ -30,10 +30,12 @@ class MainActivity : AppCompatActivity() { "Locations", "Markers", "Models", + "Multi-Floor View", "Navigation", "Paths", "Query", "Search", + "Stacked Maps", ) listView.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, demos) listView.setOnItemClickListener { _, _, position, _ -> @@ -48,10 +50,12 @@ class MainActivity : AppCompatActivity() { 7 -> startActivity(Intent(this, LocationsDemoActivity::class.java)) 8 -> startActivity(Intent(this, MarkersDemoActivity::class.java)) 9 -> startActivity(Intent(this, ModelsDemoActivity::class.java)) - 10 -> startActivity(Intent(this, NavigationDemoActivity::class.java)) - 11 -> startActivity(Intent(this, PathsDemoActivity::class.java)) - 12 -> startActivity(Intent(this, QueryDemoActivity::class.java)) - 13 -> startActivity(Intent(this, SearchDemoActivity::class.java)) + 10 -> startActivity(Intent(this, MultiFloorViewDemoActivity::class.java)) + 11 -> startActivity(Intent(this, NavigationDemoActivity::class.java)) + 12 -> startActivity(Intent(this, PathsDemoActivity::class.java)) + 13 -> startActivity(Intent(this, QueryDemoActivity::class.java)) + 14 -> startActivity(Intent(this, SearchDemoActivity::class.java)) + 15 -> startActivity(Intent(this, StackedMapsDemoActivity::class.java)) } } } diff --git a/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MultiFloorViewDemoActivity.kt b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MultiFloorViewDemoActivity.kt new file mode 100644 index 0000000..6d24c09 --- /dev/null +++ b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MultiFloorViewDemoActivity.kt @@ -0,0 +1,129 @@ +package com.mappedin.demo + +import android.os.Bundle +import android.util.Log +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ProgressBar +import androidx.appcompat.app.AppCompatActivity +import com.mappedin.MapView +import com.mappedin.models.Floor +import com.mappedin.models.FloorUpdateState +import com.mappedin.models.GetMapDataWithCredentialsOptions +import com.mappedin.models.MapDataType +import com.mappedin.models.Show3DMapOptions + +class MultiFloorViewDemoActivity : AppCompatActivity() { + private lateinit var mapView: MapView + private lateinit var loadingIndicator: ProgressBar + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + title = "Multi-Floor View" + + // Create a FrameLayout to hold both the map view and loading indicator + val container = FrameLayout(this) + + mapView = MapView(this) + container.addView( + mapView.view, + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ), + ) + + // Add loading indicator + loadingIndicator = ProgressBar(this) + val loadingParams = + FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ) + loadingParams.gravity = Gravity.CENTER + container.addView(loadingIndicator, loadingParams) + + setContentView(container) + + // See Trial API key Terms and Conditions + // https://developer.mappedin.com/docs/demo-keys-and-maps + val options = + GetMapDataWithCredentialsOptions( + key = "mik_yeBk0Vf0nNJtpesfu560e07e5", + secret = "mis_2g9ST8ZcSFb5R9fPnsvYhrX3RyRwPtDGbMGweCYKEq385431022", + mapId = "67a6641530e940000bac3c1a", + ) + + // Load the map data. + mapView.getMapData(options) { result -> + result + .onSuccess { + Log.d("MappedinDemo", "getMapData success") + + // Display the map with multi-floor view enabled. + val show3dMapOptions = + Show3DMapOptions( + multiFloorView = + Show3DMapOptions.MultiFloorViewOptions( + enabled = true, +// TODO remove commented code after fix released. +// floorGap = 10.0, +// updateCameraElevationOnFloorChange = true, + ), + ) + + mapView.show3dMap(show3dMapOptions) { r -> + r.onSuccess { + runOnUiThread { + loadingIndicator.visibility = android.view.View.GONE + } + onMapReady(mapView) + } + r.onFailure { + runOnUiThread { + loadingIndicator.visibility = android.view.View.GONE + } + Log.e("MappedinDemo", "show3dMap error: $it") + } + } + }.onFailure { + Log.e("MappedinDemo", "getMapData error: $it") + } + } + } + + // Place your code to be called when the map is ready here. + private fun onMapReady(mapView: MapView) { + Log.d("MappedinDemo", "show3dMap success - Map displayed with multi-floor view") + + // Get all floors and find the ones needed. + mapView.mapData.getByType(MapDataType.FLOOR) { result -> + result.onSuccess { floors -> + // Set the current floor to the one with elevation 9. + val floor9 = floors.find { it.elevation == 9.0 } + if (floor9 != null) { + mapView.setFloor(floor9.id) { + Log.d("MappedinDemo", "Set floor to elevation 9: ${floor9.name}") + } + } + + // Show the 6th floor (elevation 6) as well. + val floor6 = floors.find { it.elevation == 6.0 } + if (floor6 != null) { + mapView.updateState( + floor6, + FloorUpdateState( + geometry = FloorUpdateState.Geometry(visible = true), + ), + ) { + Log.d("MappedinDemo", "Made floor with elevation 6 visible: ${floor6.name}") + } + } + } + result.onFailure { + Log.e("MappedinDemo", "Failed to get floors: $it") + } + } + } +} diff --git a/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsDemoActivity.kt b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsDemoActivity.kt new file mode 100644 index 0000000..764037e --- /dev/null +++ b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsDemoActivity.kt @@ -0,0 +1,227 @@ +package com.mappedin.demo + +import android.os.Bundle +import android.util.Log +import android.view.Gravity +import android.view.ViewGroup +import android.widget.Button +import android.widget.CheckBox +import android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.ProgressBar +import android.widget.SeekBar +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.cardview.widget.CardView +import com.mappedin.MapView +import com.mappedin.models.GetMapDataWithCredentialsOptions +import com.mappedin.models.Show3DMapOptions + +class StackedMapsDemoActivity : AppCompatActivity() { + private lateinit var mapView: MapView + private lateinit var loadingIndicator: ProgressBar + + private var animate = true + private var distanceBetweenFloors = 10.0 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + title = "Stacked Maps" + + // Create a FrameLayout to hold both the map view and controls + val container = FrameLayout(this) + + mapView = MapView(this) + container.addView( + mapView.view, + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + ), + ) + + // Add loading indicator + loadingIndicator = ProgressBar(this) + val loadingParams = + FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ) + loadingParams.gravity = Gravity.CENTER + container.addView(loadingIndicator, loadingParams) + + // Add control panel + val controlPanel = createControlPanel() + val controlParams = + FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ) + controlParams.gravity = Gravity.TOP or Gravity.START + controlParams.setMargins(32, 32, 32, 32) + container.addView(controlPanel, controlParams) + + setContentView(container) + + // See Trial API key Terms and Conditions + // https://developer.mappedin.com/docs/demo-keys-and-maps + val options = + GetMapDataWithCredentialsOptions( + key = "mik_yeBk0Vf0nNJtpesfu560e07e5", + secret = "mis_2g9ST8ZcSFb5R9fPnsvYhrX3RyRwPtDGbMGweCYKEq385431022", + mapId = "666ca6a48dd908000bf47803", + ) + + // Load the map data. + mapView.getMapData(options) { result -> + result + .onSuccess { + Log.d("MappedinDemo", "getMapData success") + + // Display the map with higher pitch for better stacked view. + val show3dMapOptions = + Show3DMapOptions( + pitch = 80.0, + ) + + mapView.show3dMap(show3dMapOptions) { r -> + r.onSuccess { + runOnUiThread { + loadingIndicator.visibility = android.view.View.GONE + } + onMapReady(mapView) + } + r.onFailure { + runOnUiThread { + loadingIndicator.visibility = android.view.View.GONE + } + Log.e("MappedinDemo", "show3dMap error: $it") + } + } + }.onFailure { + Log.e("MappedinDemo", "getMapData error: $it") + } + } + } + + private fun createControlPanel(): CardView { + val card = CardView(this) + card.radius = 16f + card.cardElevation = 8f + card.setCardBackgroundColor(0xFFFFFFFF.toInt()) + + val layout = LinearLayout(this) + layout.orientation = LinearLayout.VERTICAL + layout.setPadding(32, 32, 32, 32) + + // Expand button + val expandButton = + Button(this).apply { + text = "Expand" + setOnClickListener { + StackedMapsUtils.expandFloors( + mapView, + ExpandOptions( + distanceBetweenFloors = distanceBetweenFloors, + animate = animate, + ), + ) + } + } + layout.addView(expandButton) + + // Collapse button + val collapseButton = + Button(this).apply { + text = "Collapse" + setOnClickListener { + StackedMapsUtils.collapseFloors( + mapView, + CollapseOptions( + animate = animate, + ), + ) + } + } + layout.addView(collapseButton) + + // Animate checkbox + val animateCheckbox = + CheckBox(this).apply { + text = "Animate" + isChecked = animate + setOnCheckedChangeListener { _, isChecked -> + animate = isChecked + } + } + layout.addView(animateCheckbox) + + // Floor gap label + val floorGapLabel = + TextView(this).apply { + text = "Floor Gap:" + setPadding(0, 24, 0, 8) + } + layout.addView(floorGapLabel) + + // Floor gap value display + val gapValueDisplay = + TextView(this).apply { + text = "${distanceBetweenFloors.toInt()}m" + } + + // Floor gap slider + val floorGapSlider = + SeekBar(this).apply { + max = 50 + progress = distanceBetweenFloors.toInt() + setOnSeekBarChangeListener( + object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged( + seekBar: SeekBar?, + progress: Int, + fromUser: Boolean, + ) { + distanceBetweenFloors = progress.toDouble() + gapValueDisplay.text = "${progress}m" + + // Automatically expand floors with new gap value + if (fromUser) { + StackedMapsUtils.expandFloors( + mapView, + ExpandOptions( + distanceBetweenFloors = distanceBetweenFloors, + animate = animate, + ), + ) + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }, + ) + } + layout.addView(floorGapSlider) + layout.addView(gapValueDisplay) + + card.addView(layout) + return card + } + + // Place your code to be called when the map is ready here. + private fun onMapReady(mapView: MapView) { + Log.d("MappedinDemo", "show3dMap success - Map displayed") + + // Hide the outdoor map and configure camera for stacked view. + mapView.outdoor.hide() + mapView.camera.setMaxPitch(88.0) + mapView.camera.set( + com.mappedin.models.CameraTarget( + pitch = 75.0, + ), + ) + } +} + diff --git a/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsUtils.kt b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsUtils.kt new file mode 100644 index 0000000..85f626b --- /dev/null +++ b/SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsUtils.kt @@ -0,0 +1,211 @@ +package com.mappedin.demo + +import com.mappedin.MapView +import com.mappedin.data.MapData +import com.mappedin.models.Floor +import com.mappedin.models.FloorUpdateState +import com.mappedin.models.MapDataType + +/** + * Options for expanding floors in a stacked view. + * + * @param distanceBetweenFloors The vertical spacing between floors in meters. Default: 10 + * @param animate Whether to animate the floor expansion. Default: true + * @param cameraPanMode The camera pan mode to use ("default" or "elevation"). Default: "elevation" + */ +data class ExpandOptions( + val distanceBetweenFloors: Double = 10.0, + val animate: Boolean = true, + val cameraPanMode: String = "elevation", +) + +/** + * Options for collapsing floors back to their original positions. + * + * @param animate Whether to animate the floor collapse. Default: true + */ +data class CollapseOptions( + val animate: Boolean = true, +) + +/** + * Utility object for managing stacked floor views. + * + * Provides functions to expand all floors vertically (stacked view) and collapse them back + * to a single floor view. This creates a 3D exploded view effect where all floors are visible + * at different altitudes. + * + * Example usage: + * ```kotlin + * // Expand floors with default options + * StackedMapsUtils.expandFloors(mapView) + * + * // Expand floors with custom gap + * StackedMapsUtils.expandFloors(mapView, ExpandOptions(distanceBetweenFloors = 20.0)) + * + * // Collapse floors back + * StackedMapsUtils.collapseFloors(mapView) + * ``` + */ +object StackedMapsUtils { + + /** + * Expands all floors vertically to create a stacked view. + * + * Each floor is positioned at an altitude based on its elevation multiplied by the + * distance between floors. This creates a 3D exploded view where all floors are visible. + * + * @param mapView The MapView instance + * @param options Options controlling the expansion behavior + */ + fun expandFloors( + mapView: MapView, + options: ExpandOptions = ExpandOptions(), + ) { + // Set camera pan mode to elevation for better navigation in stacked view + mapView.camera.setPanMode(options.cameraPanMode) + + // Get the current floor ID to identify the active floor + mapView.currentFloor { currentFloorResult -> + val currentFloorId = currentFloorResult.getOrNull()?.id + + // Get all floors + mapView.mapData.getByType(MapDataType.FLOOR) { result -> + result.onSuccess { floors -> + floors.forEach { floor -> + val newAltitude = floor.elevation * options.distanceBetweenFloors + val isCurrentFloor = floor.id == currentFloorId + + // First, make sure the floor is visible + mapView.getState(floor) { stateResult -> + stateResult.onSuccess { currentState -> + if (currentState != null && + (!currentState.visible || !currentState.geometry.visible) + ) { + // Make the floor visible first with 0 opacity if not current + mapView.updateState( + floor, + FloorUpdateState( + visible = true, + altitude = 0.0, + geometry = + FloorUpdateState.Geometry( + visible = true, + opacity = if (isCurrentFloor) 1.0 else 0.0, + ), + ), + ) + } + + // Then animate or update to the new altitude + if (options.animate) { + mapView.animateState( + floor, + FloorUpdateState( + altitude = newAltitude, + geometry = + FloorUpdateState.Geometry( + opacity = 1.0, + ), + ), + ) + } else { + mapView.updateState( + floor, + FloorUpdateState( + altitude = newAltitude, + visible = true, + geometry = + FloorUpdateState.Geometry( + visible = true, + opacity = 1.0, + ), + ), + ) + } + } + } + } + } + } + } + } + + /** + * Collapses all floors back to their original positions. + * + * Floors are returned to altitude 0, and only the current floor remains fully visible. + * Other floors are hidden to restore the standard single-floor view. + * + * @param mapView The MapView instance + * @param options Options controlling the collapse behavior + */ + fun collapseFloors( + mapView: MapView, + options: CollapseOptions = CollapseOptions(), + ) { + // Reset camera pan mode to default + mapView.camera.setPanMode("default") + + // Get the current floor ID to identify the active floor + mapView.currentFloor { currentFloorResult -> + val currentFloorId = currentFloorResult.getOrNull()?.id + + // Get all floors + mapView.mapData.getByType(MapDataType.FLOOR) { result -> + result.onSuccess { floors -> + floors.forEach { floor -> + val isCurrentFloor = floor.id == currentFloorId + + if (options.animate) { + // Animate to altitude 0 and fade out non-current floors + mapView.animateState( + floor, + FloorUpdateState( + altitude = 0.0, + geometry = + FloorUpdateState.Geometry( + opacity = if (isCurrentFloor) 1.0 else 0.0, + ), + ), + ) + + // After animation, hide non-current floors + if (!isCurrentFloor) { + // Use a handler to delay hiding the floor + android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({ + mapView.updateState( + floor, + FloorUpdateState( + visible = false, + altitude = 0.0, + geometry = + FloorUpdateState.Geometry( + visible = false, + opacity = 0.0, + ), + ), + ) + }, 1000) // Default animation duration + } + } else { + mapView.updateState( + floor, + FloorUpdateState( + altitude = 0.0, + visible = isCurrentFloor, + geometry = + FloorUpdateState.Geometry( + visible = isCurrentFloor, + opacity = if (isCurrentFloor) 1.0 else 0.0, + ), + ), + ) + } + } + } + } + } + } +} + diff --git a/readme.md b/readme.md index 421d9da..a30ddc3 100644 --- a/readme.md +++ b/readme.md @@ -18,17 +18,20 @@ The following table lists the sample activities that pertain to the latest versi | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | [DisplayMapDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/DisplayMapDemoActivity.kt) | The most basic example do show a map. | [Getting Started](https://developer.mappedin.com/android-sdk/getting-started) | | [AreaShapesDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/AreaShapesDemoActivity.kt) | Demonstrates using shapes to show areas and route directions around closed areas. | Coming Soon | -| [BuildingFloorSelectionDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/BuildingFloorSelectionDemoActivity.kt) | Demonstrates switching between maps for venues with multiple floors and or multiple buildings. | Coming Soon | +| [BuildingFloorSelectionDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/BuildingFloorSelectionDemoActivity.kt) | Demonstrates switching between maps for venues with multiple floors and or multiple buildings. | [Building & Floor Selection](https://developer.mappedin.com/android-sdk/level-selection) | | [CameraDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/CameraDemoActivity.kt) | Demonstrates how to move the camera. | Coming Soon | | [Image3DDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/Image3DDemoActivity.kt) | Demonstrates how to add images on a map. | Coming Soon | -| [InteractivityDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/InteractivityDemoActivity.kt) | Demonstrates how to capture and act on touch events. | Coming Soon | -| [LabelsDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/LabelsDemoActivity.kt) | Demonstrates adding rich labels to the map. | Coming Soon | -| [MarkersDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MarkersDemoActivity.kt) | Demonstrates adding HTML Markers to the map. | Coming Soon | +| [InteractivityDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/InteractivityDemoActivity.kt) | Demonstrates how to capture and act on touch events. | [Interactivity](https://developer.mappedin.com/android-sdk/interactivity) | +| [LabelsDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/LabelsDemoActivity.kt) | Demonstrates adding rich labels to the map. | [Labels](https://developer.mappedin.com/android-sdk/labels) | +| [LocationsDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/LocationsDemoActivity.kt) | Demonstrates using location profiles and categories. | [Location Profiles & Categories](https://developer.mappedin.com/android-sdk/location-profiles-categories) | +| [MarkersDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MarkersDemoActivity.kt) | Demonstrates adding HTML Markers to the map. | [Markers](https://developer.mappedin.com/android-sdk/markers) | | [ModelsDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/ModelsDemoActivity.kt) | Demonstrates adding 3D models to the map. | Coming Soon | +| [MultiFloorViewDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/MultiFloorViewDemoActivity.kt) | Demonstrates using multi floor view. | [Multi Floor View & Stacked Maps](https://developer.mappedin.com/android-sdk/stacked-maps) | [NavigationDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/NavigationDemoActivity.kt) | Demonstrates wayfinding and navigation across multiple floors. | Coming Soon | | [PathsDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/PathsDemoActivity.kt) | Demonstrates how to draw a path between two rooms. | Coming Soon | | [QueryDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/QueryDemoActivity.kt) | Demonstrates how to find the nearest room based on a coordinate and click event. | Coming Soon | | [SearchDemoActivity](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/SearchDemoActivity.kt) | Demonstrates how to use the suggest and search feature. | Coming Soon | +| [StackedMapsDemoActivity.kt](./SDKv6_Examples/PlaygroundSamples/app/src/main/java/com/mappedin/demo/StackedMapsDemoActivity.kt) | Demonstrates how to use the stacked maps. | [Multi Floor View & Stacked Maps](https://developer.mappedin.com/android-sdk/stacked-maps) | ---