mapbox / mapbox/mapbox-maps-android

Android Auto map freezes when app is backgrounded on Samsung Android 16 (Mapbox v11)

Open
#2,716 8 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug :beetle:
Dominant language
Kotlin
Stars
578
Forks
161
PR merge metrics
No merged PRs in 30d

Description

Environment

  • Android OS version: Android 16
  • Devices affected: Galaxy S25 Ultra (and multiple new Samsung models)
  • Maps SDK Version: 11.20.1
  • Mapbox Android Auto Extension: 11.20.1
  • Android Car App Library: 1.7.0
  • Working devices: Pixel (Android 16) and Samsung (Android <16)

Observed behavior and steps to reproduce

I am observing an issue where the Mapbox map rendered in Android Auto stops updating when the mobile app is backgrounded on specific Samsung devices running Android 16.

The issue does not occur on:

Google Pixel devices running Android 16
Samsung devices running lower Android versions

This suggests a device/vendor-specific behavior affecting Mapbox rendering or camera updates when the app is backgrounded.

Steps to reproduce:

  1. Launch the app on a Samsung device (Android 16)
  2. Connect to Android Auto (Desktop Head Unit or real car)
  3. Render a Mapbox map using MapboxCarMap
  4. Enable location puck + follow camera (viewport follow puck)
  5. Start moving (real or simulated location)
  6. Background the mobile app (home button or switch apps)
  7. Observe Android Auto screen

Expected behavior

  • Location puck continues updating
  • Camera continues following location
  • Map continues rendering smoothly

Notes / preliminary analysis

Additional Notes / Hypothesis:
The issue appears to be related to Samsung’s background performance policies on Android 16
It seems that animation or rendering loops are being suspended when the app is not in foreground
Mapbox camera updates using animation or viewport transitions may be affected

Notably:

Using setCamera() (non-animated) appears to still work in some cases
Animated transitions (viewport / easeTo) and puck movement appear to stop completely

Additional links and references

This log appears exactly when the app is backgrounded:
Choreographer: CoreRune.SYSPERF_ACTIVE_APP_BBA_ENABLE : stop animation in background states

Minimal Repro

A minimal app was created with:

Mapbox Compose on phone
Mapbox Android Auto extension
Viewport follow-puck camera

The issue is reproducible consistently on Samsung Android 16.
Main Activity:

class MainActivity : ComponentActivity() {

    private var hasLocationPermission by mutableStateOf(false)

    private val requestLocationPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            hasLocationPermission = granted
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        hasLocationPermission = ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED

        if (!hasLocationPermission) {
            requestLocationPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION)
        }

        setContent {
            val mapViewportState = rememberMapViewportState()

            MainMapScreen(
                hasLocationPermission = hasLocationPermission,
                mapViewportState = mapViewportState
            )
        }
    }
}

@Composable
private fun MainMapScreen(
    hasLocationPermission: Boolean,
    mapViewportState: MapViewportState
) {
    MapboxMap(
        modifier = Modifier.fillMaxSize(),
        mapViewportState = mapViewportState,
        style = {
            MapboxStandardStyle()
        },
        scaleBar = {
            ScaleBar(Modifier.padding(top = 60.dp))
        },
        logo = {
            Logo(Modifier.padding(bottom = 40.dp))
        },
        attribution = {
            Attribution(Modifier.padding(bottom = 40.dp))
        }
    ) {
        MapEffect(hasLocationPermission) { mapView ->
            val locationPlugin = mapView.location

            if (hasLocationPermission) {
                locationPlugin.updateSettings {
                    enabled = true
                    puckBearingEnabled = true
                    puckBearing = PuckBearing.HEADING
                    locationPuck = createDefault2DPuck(withBearing = true)
                }
            }
        }
    }

    LaunchedEffect(hasLocationPermission) {
        if (hasLocationPermission) {
            mapViewportState.transitionToFollowPuckState(
                FollowPuckViewportStateOptions.Builder()
                    .zoom(16.0)
                    .pitch(0.0)
                    .build()
            )
        } else {
            mapViewportState.setCameraOptions {
                zoom(2.0)
                center(Point.fromLngLat(-98.0, 39.5))
                pitch(0.0)
                bearing(0.0)
            }
        }
    }
}

Android auto related code:

class MyCarAppService : CarAppService() {
    override fun createHostValidator(): HostValidator {
        return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
    }

    override fun onCreateSession(): Session = MyCarSession()
}

class MyCarSession : Session() {
    private val mapboxCarMap = mapboxMapInstaller()
        .onCreated(TestLandingScreenCameraController())
        .install { carContext ->
            // Callback is triggered when the Session calls onCreate. This allows you to specify
            // custom MapInitOptions.
            MapInitOptions(carContext)
        }
    override fun onCreateScreen(intent: android.content.Intent): Screen {
        return MyCarScreen(carContext)
    }
}
class MyCarScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {

        val temp = NavigationTemplate.Builder()
        val actionStrip = ActionStrip.Builder()
        actionStrip.addAction(Action.PAN)
        temp.setActionStrip(actionStrip.build())
        return temp.build()
    }
}

class TestLandingScreenCameraController : MapboxCarMapObserver {
    private var mapBoxMap : MapboxMap? = null
    private var mapSurface: MapSurface? = null
    
    override fun onAttached(mapboxCarMapSurface: MapboxCarMapSurface) {
        val mapboxMap = mapboxCarMapSurface.mapSurface.getMapboxMap()
        val mapSurface = mapboxCarMapSurface.mapSurface
        this.mapBoxMap = mapboxMap
        this.mapSurface = mapSurface

        mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) {

            mapSurface.location.updateSettings {

                enabled = true
                pulsingEnabled = true
            }

        }
        val followPuckState = mapSurface.viewport.makeFollowPuckViewportState(
            FollowPuckViewportStateOptions.Builder()
                .zoom(16.0)
                .build()
        )

        mapSurface.viewport.transitionTo(followPuckState)
    }

    override fun onDetached(mapboxCarMapSurface: MapboxCarMapSurface) {

    }

}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal repro's MainActivity and the Android Auto entry points MyCarAppService, MyCarSession, and TestLandingScreenCameraController. Run it on a Samsung device with Android 16, background the mobile app, and compare animated viewport and puck updates with setCamera() behavior and the Choreographer log. Done means the Android Auto map, location puck, and follow camera continue updating while the app is backgrounded.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.