Maps Perspective Change
This example demonstrates how to toggle the map view between 2D (a vertical look-down at the map) and 3D (a tilted, perspective view looking towards the horizon). A floating button switches between the two, and the transition is animated.
Map Display and UI
MainActivity overrides onCreate, which inflates the view binding, calls setContentView(binding.root) for the layout in res/layout/activity_main.xml, and enables edge-to-edge drawing so the map fills the screen. It then wires up the toggle button in setupUi() and registers the SDK listeners.
When the activity is destroyed, onDestroy clears the listeners, deinitializes the SDK with GemSdk.release(), and exits the process so all native resources are freed.
The layout hosts a full-screen com.magiclane.sdk.core.GemSurfaceView that renders the map, with a circular MaterialButton anchored to the bottom-right corner. The button starts showing the 3D icon, indicating that a tap switches the map to 3D.
Toggling the Perspective
The activity keeps the currently applied perspective in currentPerspective, initialized to EMapViewPerspective.TwoDimensional so the map opens in 2D. Each tap calls togglePerspective(), which:
- Picks the perspective to switch to (the opposite of the current one).
- Updates the button's icon and content description to reflect the action the next tap will perform.
- Applies the new perspective with
setMapViewPerspective, animated viaAnimation(EAnimation.Linear, 300)- a linear transition over 300 ms.
The call to setMapViewPerspective accesses the map engine, so it must run on the map engine's thread. Wrapping it in SdkCall.execute schedules it on that thread; calling SDK methods directly from the UI thread would throw an exception.
Reacting to SDK Initialization and Map Events
registerSdkListeners() wires up the SDK callbacks. onSdkInitFailed shows an error dialog and closes the activity if the SDK cannot initialize, onDefaultMapViewCreated aligns the Magic Lane logo once the map is ready, onSurfaceChanged re-aligns it on resize (e.g. rotation), and SdkSettings.onApiTokenRejected warns the user when the API token is invalid. The UI work is marshalled onto the main thread by runOnAliveUi, which only runs while the activity is still alive.
Keeping the Logo Clear of the System Bars
Because the map draws edge-to-edge, it extends underneath the toolbar and the system bars. updateFocusViewport() sets the map view's focusViewport to the region left after subtracting the system window insets, so the Magic Lane logo stays visible. Map access must run on the SDK thread, so the work is wrapped in SdkCall.runSynced.
Releasing the Listeners
clearSdkListeners() is called from onDestroy to detach every callback before the activity goes away. Resetting the listeners to empty lambdas guarantees that a late SDK callback can never touch a destroyed activity.

