Android predictive back
The predictive back gesture (introduced in Android 13 / API 33, enabled by default for opted-in apps from Android 15) shows a peek of where Back will go before the user commits. Apps MUST migrate off the unsupported onBackPressed() and KEYCODE_BACK interception to OnBackPressedDispatcher and SHOULD drive in-app transitions from the gesture's progress.
Migrate off unsupported back handling
Activity.onBackPressed()andDialog.onBackPressed()are deprecated; interceptingKeyEvent.KEYCODE_BACKis no longer supported. Code MUST NOT rely on either — official docs warn of "unexpected behavior in a future release."- Custom back logic MUST register an
OnBackPressedCallbackon the activity'sOnBackPressedDispatcher, tied to aLifecycleOwnerso it is removed automatically. - Prefer the AndroidX
androidx.activityAPIs over the platformOnBackInvokedCallback— AndroidX is backward compatible across versions and is the recommended path. Use the platformOnBackInvokedCallbackdirectly ONLY when you have no AndroidX dependency. - The callback's
isEnabledMUST be derived from observable UI state (aStateFlowor ComposeState), not toggled imperatively, so the system knows whether the app or the system handles Back. - Keep callbacks single-responsibility: one callback per back-consuming UI state, ordered by registration. The most recently added enabled callback wins.
val callback = object : OnBackPressedCallback(enabled = uiState.hasUnsavedChanges) {
override fun handleOnBackPressed() { showDiscardConfirmation() }
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
Opt in via the manifest
- The
android:enableOnBackInvokedCallbackflag controls predictive back during migration. It is a per-<application>flag and MAY be overridden per<activity>for gradual rollout of multi-activity apps. - Setting it
falsedisables system predictive animations and ignores the platformOnBackInvokedCallback; AndroidXOnBackPressedCallbackstill works. Set ittrue(or omit it where the default is on) to receive system animations. - FORECAST: default-on behavior and removal of any opt-out are tied to evolving target-SDK rules across Android 15/16 (API 35/36). Pin the exact behavior to your
targetSdkand re-check the linked doc before shipping — do not assume a fixed default across versions.
Drive in-app animations from gesture progress
- For custom transitions (sheets, drawers, multi-step flows), guidance SHOULD animate with the gesture rather than snapping at release.
- Compose: use
PredictiveBackHandler, collecting theFlow<BackEventCompat>and readingprogress(0f..1f). Commit the navigation when the flow completes; reset UI onCancellationException(gesture cancelled). - Views: extend
OnBackPressedCallbackand implementhandleOnBackStarted/handleOnBackProgressed/handleOnBackCancelled(API 34+) to animate, withhandleOnBackPressedcommitting the result.
PredictiveBackHandler(enabled = sheetIsOpen) { progress: Flow<BackEventCompat> ->
try {
progress.collect { event -> sheetOffset = event.progress }
closeSheet() // committed
} catch (e: CancellationException) {
resetSheetOffset() // cancelled
}
}
Observer-only callbacks
- Android 16 (API 36) adds
PRIORITY_SYSTEM_NAVIGATION_OBSERVERfor callbacks that watch Back without consuming it (e.g. analytics). Use it ONLY for non-consuming side effects; it MUST NOT alter navigation.