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)?