Toggle the predictive back animation at runtime on Android 14+ (targetSdk 34+)


I have an Android app (Kotlin + Jetpack Compose) with a settings switch that should let the user disable the predictive back animation. The app already opts in globally in the manifest:

<application android:name=".MyApplication" ...... android:enableOnBackInvokedCallback="true" ......>

Environment: compileSdk = 37, targetSdk = 37, minSdk = 27.

Navhost configuration:

val onBack: () -> Unit = { navController.popBackStack() }
NavHost(
    navController = navController,
    startDestination = HomeRoute,

    enterTransition = {
        slideIntoContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.Start,
            animationSpec = tween(450, easing = FastOutSlowInEasing)
        ) + fadeIn(animationSpec = tween(450))
    },

    exitTransition = {
        slideOutOfContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.Start,
            targetOffset = { it / 3 }, 
            animationSpec = tween(450, easing = FastOutSlowInEasing)
        ) + scaleOut(targetScale = 0.9f) + fadeOut(animationSpec = tween(300))
    },
 
    popEnterTransition = {
        slideIntoContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.End,
            initialOffset = { it / 3 },
            animationSpec = tween(450, easing = FastOutSlowInEasing)
        ) + scaleIn(initialScale = 0.9f) + fadeIn(animationSpec = tween(450))
    },

    popExitTransition = {
        slideOutOfContainer(
            towards = AnimatedContentTransitionScope.SlideDirection.End,
            animationSpec = tween(450, easing = FastOutSlowInEasing)
        ) + fadeOut(animationSpec = tween(300))
    }
){
    composable<WatchHistoryRoute> {
        WatchHistoryRouteScreen(
            onBack = onBack,
            onNavigateToVideo = onNavigateToVideo,
        )
    }
}

// WatchHistoryScreen
//......
Scaffold(
    modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
    title = stringResource(R.string.my_subscribe),
    onBack = onBack,
    scrollBehavior = scrollBehavior,
) 
//......

The switch value is stored in SharedPreferences and works fine.

What I've tried: A global BackHandler inside MainActivity#setContent:

BackHandler(Preferences.disablePredictiveBack) {
   navController.popBackStack() 
}

This completely breaks back navigation. Because it's composed last, it's registered last on OnBackPressedDispatcher, so it has the highest priority and shadows every other BackHandler in the app (the exit-confirmation dialog on the home screen, the drawer-close handler, the search-focus handler, etc.). On top of that, on the root destination popBackStack() returns false, so the app can't even exit.

Question: Is there any public API to enable/disable predictive back at runtime based on a user setting, or is android:enableOnBackInvokedCallback a purely static manifest flag with no runtime equivalent on Android 14+? If a runtime toggle isn't possible, is there a recommended workaround to achieve the same UX (back gesture only fires after release)?

0
Sep 4 at 12:09 PM
User AvatarMikoto Misaka
#android#android-jetpack-compose

No answer found for this question yet.