Add support for the predictive back gesture

Figure 1. Mockup of the predictive back gesture look and feel on a phone

Predictive Back, a gesture navigation feature, lets users preview where the back swipe takes them.

For example, using a back gesture can display an animated preview of the Home screen behind your app, as presented in the mockup in figure 1.

Starting with Android 15, the developer option for predictive back animations is no longer available. System animations such as back-to-home, cross-task, and cross-activity now appear for apps that have opted in to the predictive back gesture either entirely or at an activity level.

You can test this back-to-home animation (as described in a following section of this page).

Supporting the predictive back gesture requires updating your app, using the backward compatible OnBackPressedCallback AppCompat 1.6.0-alpha05 (AndroidX) or higher API, or using the new OnBackInvokedCallback platform API. Most apps use the backward compatible AndroidX API.

This update provides a migration path to properly intercept back navigation, which involves replacing back interceptions from KeyEvent.KEYCODE_BACK and any classes with onBackPressed methods such as Activity and Dialog with the new system Back APIs.

Codelab and Google I/O video

In addition to using this documentation on this page, try out our codelab. It provides a common use-case implementation of a WebView handling the predictive back gesture using AndroidX Activity APIs.

You can also view our Google I/O video, which covers additional examples of implementing the AndroidX and platform APIs.

Update an app that uses default back navigation

Updating your app to support this feature is straightforward if your app doesn't implement any custom back behavior (in other words, it leaves back handling up to the system). Opt-in to this feature as described in this guide.

If your app uses Fragments or the Navigation Component, also upgrade to AndroidX Activity 1.6.0-alpha05 or higher.

Update an app that uses custom back navigation

If your app implements custom back behavior, there are different migration paths depending on whether it uses AndroidX and how it handles back navigation.

Your app uses AndroidX How your app handles back navigation Recommended migration path (link on this page)
Yes AndroidX APIs Migrate an existing AndroidX back implementation
Unsupported platform APIs Migrate an AndroidX app containing unsupported back navigation APIs to AndroidX APIs
No Unsupported platform APIs, able to migrate Migrate an app that uses unsupported back navigation APIs to platform APIs
Unsupported platform APIs, but unable to migrate Defer opt-in until this becomes a required feature

Migrate an AndroidX back navigation implementation

This use case is the most common (and the most recommended). It applies to new or existing apps that implement custom gesture navigation handling with OnBackPressedDispatcher, as described in Provide custom back navigation.

If your app fits into this category, follow these steps to add support for the predictive back gesture:

  1. To ensure that APIs that are already using OnBackPressedDispatcher APIs (such as Fragments and the Navigation Component) work seamlessly with the predictive back gesture, upgrade to AndroidX Activity 1.6.0-alpha05.

    // In your build.gradle file:
    dependencies {
    
    // Add this in addition to your other dependencies
    implementation "androidx.activity:activity:1.6.0-alpha05"
    
  2. Opt-in to the predictive back gesture, as described on this page.

Migrate an AndroidX app containing unsupported back navigation APIs to AndroidX APIs

If your app uses AndroidX libraries but implements or makes reference to the unsupported back navigation APIs, you’ll need to migrate to using AndroidX APIs to support the new behavior.

To migrate unsupported APIs to AndroidX APIs:

  1. Migrate your system Back handling logic to AndroidX’s OnBackPressedDispatcher with an implementation of OnBackPressedCallback. For detailed guidance, see Provide custom back navigation.

  2. Disable the OnBackPressedCallback when ready to stop intercepting the back gesture.

  3. Stop intercepting back events via OnBackPressed or KeyEvent.KEYCODE_BACK.

  4. Make sure to upgrade to AndroidX Activity 1.6.0-alpha05.

    // In your build.gradle file:
    dependencies {
    
    // Add this in addition to your other dependencies
    implementation "androidx.activity:activity:1.6.0-alpha05"
    
  5. When you have successfully migrated your app, opt-in to the predictive back gesture (as described on this page) to see the back-to-home system animation.

Migrate an app that uses unsupported back navigation APIs to platform APIs

If your app cannot use AndroidX libraries and instead implements or makes reference to custom Back navigation using the unsupported APIs, you must migrate to the OnBackInvokedCallback platform API.

Complete the following steps to migrate unsupported APIs to the platform API:

  1. Use the new OnBackInvokedCallback API on devices running Android 13 or higher, and rely on the unsupported APIs on devices running Android 12 or lower.

  2. Register your custom back logic in OnBackInvokedCallback with onBackInvokedDispatcher. This prevents the current activity from being finished, and your callback gets a chance to react to the Back action once the user completes the system Back navigation.

  3. Unregister the OnBackInvokedCallback when ready to stop intercepting the back gesture. Otherwise, users may see undesirable behavior when using a system Back navigation—for example, "getting stuck" between views and forcing them to force quit your app.

    Here’s an example of how to migrate logic out of onBackPressed:

    Kotlin

    @Override
    fun onCreate() {
        if (BuildCompat.isAtLeastT()) {
            onBackInvokedDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT
            ) {
                /**
                 * onBackPressed logic goes here. For instance:
                 * Prevents closing the app to go home screen when in the
                 * middle of entering data to a form
                 * or from accidentally leaving a fragment with a WebView in it
                 *
                 * Unregistering the callback to stop intercepting the back gesture:
                 * When the user transitions to the topmost screen (activity, fragment)
                 * in the BackStack, unregister the callback by using
                 * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
                 * (https://developer.android.com/reference/kotlin/android/window/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
                 */
            }
        }
    }
    

    Java

    @Override
    void onCreate() {
      if (BuildCompat.isAtLeastT()) {
        getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
            () -> {
              /**
               * onBackPressed logic goes here - For instance:
               * Prevents closing the app to go home screen when in the
               * middle of entering data to a form
               * or from accidentally leaving a fragment with a WebView in it
               *
               * Unregistering the callback to stop intercepting the back gesture:
               * When the user transitions to the topmost screen (activity, fragment)
               * in the BackStack, unregister the callback by using
               * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
               * (https://developer.android.com/reference/kotlin/android/view/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
               */
            }
        );
      }
    }
    
  4. Stop intercepting back events via OnBackPressed or KeyEvent.KEYCODE_BACK for Android 13 and later.

  5. When you have successfully migrated your app, opt-in to the predictive back gesture (as described on this page) so that OnBackInvokedCallback takes effect.

You can register an OnBackInvokedCallback with PRIORITY_DEFAULT or PRIORITY_OVERLAY, which is not available in the similar AndroidX OnBackPressedCallback. Registering a callback with PRIORITY_OVERLAY is helpful in some instances.

This applies when you migrate from onKeyPreIme() and your callback needs to receive the back gesture instead of an open IME. IMEs register callbacks with PRIORITY_DEFAULT when opened. Register your callback with PRIORITY_OVERLAY to ensure OnBackInvokedDispatcher dispatches the back gesture to your callback instead of the open IME.

Opt-in to the predictive back gesture

Once you've determined how to update your app based on your case, opt-in to supporting the predictive back gesture.

To opt-in, in AndroidManifest.xml, in the <application> tag, set the android:enableOnBackInvokedCallback flag to true.

<application
    ...
    android:enableOnBackInvokedCallback="true"
    ... >
...
</application>

If you don't provide a value, it defaults to false and does the following:

  • Disables the predictive back gesture system animation.
  • Ignores OnBackInvokedCallback, but OnBackPressedCallback calls continue to work.

Opt-in at an activity level

Starting with Android 14, the android:enableOnBackInvokedCallback flag lets you opt-in to predictive system animations at the activity level. This behavior makes it more manageable to migrate large multi-activity apps to predictive back gestures. With Android 15, predictive back is no longer behind the developer option. Apps can opt in to predictive back fully or at the activity level.

The following code shows an example of using enableOnBackInvokedCallback to enable the back-to-home system animation from the MainActivity:

<manifest ...>
    <application . . .

        android:enableOnBackInvokedCallback="false">

        <activity
            android:name=".MainActivity"
            android:enableOnBackInvokedCallback="true"
            ...
        </activity>
        <activity
            android:name=".SecondActivity"
            android:enableOnBackInvokedCallback="false"
            ...
        </activity>
    </application>
</manifest>

In the preceding example, setting android:enableOnBackInvokedCallback=true for ".SecondActivity" enables the cross-activity system animation.

Keep in mind the following considerations when using the android:enableOnBackInvokedCallback flag:

  • Setting android:enableOnBackInvokedCallback=false turns off predictive back animations either at the activity level or at the app level, depending on where you set the tag, and instructs the system to ignore calls to the OnBackInvokedCallback platform API. However, calls to OnBackPressedCallback continue to run because OnBackPressedCallback is backward compatible and calls the onBackPressed API, which is unsupported prior to Android 13.
  • Setting the enableOnBackInvokedCallback flag at the app level establishes the default value for all activities in the app. You can override the default per activity by setting the flag at the activity level, as shown in the preceding code example.

Callback best practices

Here are best practices for using the supported system back callbacks; BackHandler (for Compose), OnBackPressedCallback, or OnBackInvokedCallback.

Determine the UI State that enables and disables each callback

UI state is a property that describes the UI. We recommend following these high-level steps.

  1. Determine the UI state that enables and disables each callback.

  2. Define that state using an observable data holder type, such as StateFlow or Compose State, and enable or disable the callback as the state changes.

If your app was previously associating back logic with conditional statements, this might signify you are reacting to the back event after it has already occurred. Avoid this pattern with newer callbacks. If possible, move the callback outside of the conditional statement and instead associate the callback to an observable data holder type.

Use system back callbacks for UI Logic

UI logic dictates how to display UI. Use system back callbacks to run UI logic, such as displaying a pop-up or running an animation.

If your app enables a system back callback, the predictive animations don't run and you must handle the back event. Don't create callbacks only to run non-UI logic.

For example, if you're intercepting back events only to log, log within the Activity or Fragment lifecycle instead.

  • For activity-to-activity cases or fragment-to-activity cases, log if isFinishing within onDestroy is true within the Activity lifecycle.
  • For fragment-to-fragment cases, log if isRemoving within onDestroy is true within the Fragment's view lifecycle. Or log using onBackStackChangeStarted or onBackStackChangeCommitted methods within FragmentManager.OnBackStackChangedListener.

For the Compose case, log within the onCleared() callback of a ViewModel associated with the Compose destination. This is the best signal for knowing when a compose destination is popped off the back stack and destroyed.

Create single responsibility callbacks

You can add multiple callbacks to the dispatcher. The callbacks are added to a stack in which the last added enabled callback handles the next back gesture with one callback per back gesture.

It is easier to manage the enabled state of a callback if that callback has a single responsibility. For example:

Ordering of callbacks in a stack.
Figure 2. Callback stack diagram.

Figure 2 shows how you can have multiple callbacks in the stack, each responsible for one thing. A callback only runs if the callbacks above it in the stack are disabled. In this example, the "Are you sure..." callback is enabled when the user enters data into a form, and disabled otherwise. The callback opens a confirmation dialog when the user swipes back to exit the form.

The other callback can include a material component that supports predictive back, an AndroidX transition using the Progress APIs, or another custom callback.

A childFragmentManager's callback runs if the above callbacks are disabled and the back stack for this FragmentManager isn't empty, where childFragmentManager is attached within a Fragment. In this example, this internal callback is disabled.

Likewise, supportFragmentManager's internal callback runs if the above callbacks are disabled and its stack is non-empty. This behavior is consistent when using either FragmentManager or NavigationComponent for navigation, as NavigationComponent relies on FragmentManager. In this example, this callback runs if the user didn't enter text into the form causing the "Are you sure..." callback to be disabled.

Finally, super.onBackPressed()is the system-level callback, that again runs if the above callbacks are disabled. In order to trigger system animations such as back-to-home, cross-activity, and cross-task, supportFragmentManager's back stack must be empty so its internal callback is disabled.

Test the predictive back gesture animation

If you still use Android 13 or Android 14, you can test the back-to-home animation shown in Figure 1.

To test this animation, complete the following steps:

  1. On your device, go to Settings > System > Developer options.

  2. Select Predictive back animations.

  3. Launch your updated app, and use the back gesture to see it in action.