public final class

NavigationUI

extends java.lang.Object

 java.lang.Object

↳androidx.navigation.ui.NavigationUI

Overview

Class which hooks up elements typically in the 'chrome' of your application such as global navigation patterns like a navigation drawer or bottom nav bar with your NavController.

Summary

Methods
public static booleannavigateUp(NavController navController, AppBarConfiguration configuration)

Handles the Up button by delegating its behavior to the given NavController.

public static booleannavigateUp(NavController navController, Openable openableLayout)

Handles the Up button by delegating its behavior to the given NavController.

public static booleanonNavDestinationSelected(MenuItem item, NavController navController)

Attempt to navigate to the NavDestination associated with the given MenuItem.

public static voidsetupActionBarWithNavController(AppCompatActivity activity, NavController navController)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

public static voidsetupActionBarWithNavController(AppCompatActivity activity, NavController navController, AppBarConfiguration configuration)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

public static voidsetupActionBarWithNavController(AppCompatActivity activity, NavController navController, Openable openableLayout)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

public static voidsetupWithNavController(BottomNavigationView bottomNavigationView, NavController navController)

Sets up a for use with a NavController.

public static voidsetupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController)

Sets up a and Toolbar for use with a NavController.

public static voidsetupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController, AppBarConfiguration configuration)

Sets up a and Toolbar for use with a NavController.

public static voidsetupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController, Openable openableLayout)

Sets up a and Toolbar for use with a NavController.

public static voidsetupWithNavController(NavigationView navigationView, NavController navController)

Sets up a for use with a NavController.

public static voidsetupWithNavController(Toolbar toolbar, NavController navController)

Sets up a Toolbar for use with a NavController.

public static voidsetupWithNavController(Toolbar toolbar, NavController navController, AppBarConfiguration configuration)

Sets up a Toolbar for use with a NavController.

public static voidsetupWithNavController(Toolbar toolbar, NavController navController, Openable openableLayout)

Sets up a Toolbar for use with a NavController.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static boolean onNavDestinationSelected(MenuItem item, NavController navController)

Attempt to navigate to the NavDestination associated with the given MenuItem. This MenuItem should have been added via one of the helper methods in this class.

Importantly, it assumes the menu item id matches a valid action id or destination id to be navigated to.

By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.

Parameters:

item: The selected MenuItem.
navController: The NavController that hosts the destination.

Returns:

True if the NavController was able to navigate to the destination associated with the given MenuItem.

public static boolean navigateUp(NavController navController, Openable openableLayout)

Handles the Up button by delegating its behavior to the given NavController. This should generally be called from AppCompatActivity.onSupportNavigateUp().

If you do not have a Openable layout, you should call NavController.navigateUp() directly.

Parameters:

navController: The NavController that hosts your content.
openableLayout: The Openable layout that should be opened if you are on the topmost level of the app.

Returns:

True if the NavController was able to navigate up.

public static boolean navigateUp(NavController navController, AppBarConfiguration configuration)

Handles the Up button by delegating its behavior to the given NavController. This is an alternative to using NavController.navigateUp() directly when the given AppBarConfiguration needs to be considered when determining what should happen when the Up button is pressed.

In cases where no Up action is available, the AppBarConfiguration.getFallbackOnNavigateUpListener() will be called to provide additional control.

Parameters:

navController: The NavController that hosts your content.
configuration: Additional configuration options for determining what should happen when the Up button is pressed.

Returns:

True if the NavController was able to navigate up.

public static void setupActionBarWithNavController(AppCompatActivity activity, NavController navController)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

By calling this method, the title in the action bar will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On all other destinations, the ActionBar will show the Up button. Call NavController.navigateUp() to handle the Up button.

Destinations that implement FloatingWindow will be ignored.

Parameters:

activity: The activity hosting the action bar that should be kept in sync with changes to the NavController.
navController: The NavController that supplies the secondary menu. Navigation actions on this NavController will be reflected in the title of the action bar.

See also: NavigationUI.setupActionBarWithNavController(AppCompatActivity, NavController, AppBarConfiguration)

public static void setupActionBarWithNavController(AppCompatActivity activity, NavController navController, Openable openableLayout)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

By calling this method, the title in the action bar will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On the start destination of your navigation graph, the ActionBar will show the drawer icon if the given Openable layout is non null. On all other destinations, the ActionBar will show the Up button. Call NavigationUI.navigateUp(NavController, Openable) to handle the Up button.

Destinations that implement FloatingWindow will be ignored.

Parameters:

activity: The activity hosting the action bar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the action bar.
openableLayout: The Openable layout that should be toggled from the home button

See also: NavigationUI.setupActionBarWithNavController(AppCompatActivity, NavController, AppBarConfiguration)

public static void setupActionBarWithNavController(AppCompatActivity activity, NavController navController, AppBarConfiguration configuration)

Sets up the ActionBar returned by AppCompatActivity.getSupportActionBar() for use with a NavController.

By calling this method, the title in the action bar will automatically be updated when the destination changes (assuming there is a valid label).

The AppBarConfiguration you provide controls how the Navigation button is displayed. Call NavigationUI.navigateUp(NavController, AppBarConfiguration) to handle the Up button.

Destinations that implement FloatingWindow will be ignored.

Parameters:

activity: The activity hosting the action bar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the action bar.
configuration: Additional configuration options for customizing the behavior of the ActionBar

public static void setupWithNavController(Toolbar toolbar, NavController navController)

Sets up a Toolbar for use with a NavController.

By calling this method, the title in the Toolbar will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On all other destinations, the Toolbar will show the Up button. This method will call NavController.navigateUp() when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController that supplies the secondary menu. Navigation actions on this NavController will be reflected in the title of the Toolbar.

See also: NavigationUI.setupWithNavController(Toolbar, NavController, AppBarConfiguration)

public static void setupWithNavController(Toolbar toolbar, NavController navController, Openable openableLayout)

Sets up a Toolbar for use with a NavController.

By calling this method, the title in the Toolbar will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On the start destination of your navigation graph, the Toolbar will show the drawer icon if the given Openable layout is non null. On all other destinations, the Toolbar will show the Up button. This method will call NavigationUI.navigateUp(NavController, Openable) when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the Toolbar.
openableLayout: The Openable layout that should be toggled from the Navigation button

See also: NavigationUI.setupWithNavController(Toolbar, NavController, AppBarConfiguration)

public static void setupWithNavController(Toolbar toolbar, NavController navController, AppBarConfiguration configuration)

Sets up a Toolbar for use with a NavController.

By calling this method, the title in the Toolbar will automatically be updated when the destination changes (assuming there is a valid label).

The AppBarConfiguration you provide controls how the Navigation button is displayed and what action is triggered when the Navigation button is tapped. This method will call NavigationUI.navigateUp(NavController, AppBarConfiguration) when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the Toolbar.
configuration: Additional configuration options for customizing the behavior of the Toolbar

public static void setupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController)

Sets up a and Toolbar for use with a NavController.

By calling this method, the title in the CollapsingToolbarLayout will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On all other destinations, the Toolbar will show the Up button. This method will call NavController.navigateUp() when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

collapsingToolbarLayout: The CollapsingToolbarLayout that should be kept in sync with changes to the NavController.
toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController that supplies the secondary menu. Navigation actions on this NavController will be reflected in the title of the Toolbar.

public static void setupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController, Openable openableLayout)

Sets up a and Toolbar for use with a NavController.

By calling this method, the title in the CollapsingToolbarLayout will automatically be updated when the destination changes (assuming there is a valid label).

The start destination of your navigation graph is considered the only top level destination. On the start destination of your navigation graph, the Toolbar will show the drawer icon if the given Openable layout is non null. On all other destinations, the Toolbar will show the Up button. This method will call NavigationUI.navigateUp(NavController, Openable) when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

collapsingToolbarLayout: The CollapsingToolbarLayout that should be kept in sync with changes to the NavController.
toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the Toolbar.
openableLayout: The Openable layout that should be toggled from the Navigation button

public static void setupWithNavController(CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, NavController navController, AppBarConfiguration configuration)

Sets up a and Toolbar for use with a NavController.

By calling this method, the title in the CollapsingToolbarLayout will automatically be updated when the destination changes (assuming there is a valid label).

The AppBarConfiguration you provide controls how the Navigation button is displayed and what action is triggered when the Navigation button is tapped. This method will call NavigationUI.navigateUp(NavController, AppBarConfiguration) when the Navigation button is clicked.

Destinations that implement FloatingWindow will be ignored.

Parameters:

collapsingToolbarLayout: The CollapsingToolbarLayout that should be kept in sync with changes to the NavController.
toolbar: The Toolbar that should be kept in sync with changes to the NavController.
navController: The NavController whose navigation actions will be reflected in the title of the Toolbar.
configuration: Additional configuration options for customizing the behavior of the Toolbar

public static void setupWithNavController(NavigationView navigationView, NavController navController)

Sets up a for use with a NavController. This will call NavigationUI.onNavDestinationSelected(MenuItem, NavController) when a menu item is selected. The selected item in the NavigationView will automatically be updated when the destination changes.

If the is directly contained with an Openable layout, it will be closed when a menu item is selected.

Similarly, if the has a associated with it (as is the case when using a ), the bottom sheet will be hidden when a menu item is selected.

Parameters:

navigationView: The NavigationView that should be kept in sync with changes to the NavController.
navController: The NavController that supplies the primary and secondary menu. Navigation actions on this NavController will be reflected in the selected item in the NavigationView.

public static void setupWithNavController(BottomNavigationView bottomNavigationView, NavController navController)

Sets up a for use with a NavController. This will call NavigationUI.onNavDestinationSelected(MenuItem, NavController) when a menu item is selected. The selected item in the BottomNavigationView will automatically be updated when the destination changes.

Parameters:

bottomNavigationView: The BottomNavigationView that should be kept in sync with changes to the NavController.
navController: The NavController that supplies the primary menu. Navigation actions on this NavController will be reflected in the selected item in the BottomNavigationView.

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.navigation.ui;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.customview.widget.Openable;
import androidx.navigation.ActivityNavigator;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import androidx.navigation.NavGraph;
import androidx.navigation.NavOptions;

import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.navigation.NavigationView;

import java.lang.ref.WeakReference;
import java.util.Set;

/**
 * Class which hooks up elements typically in the 'chrome' of your application such as global
 * navigation patterns like a navigation drawer or bottom nav bar with your {@link NavController}.
 */
public final class NavigationUI {

    // No instances. Static utilities only.
    private NavigationUI() {
    }

    /**
     * Attempt to navigate to the {@link NavDestination} associated with the given MenuItem. This
     * MenuItem should have been added via one of the helper methods in this class.
     *
     * <p>Importantly, it assumes the {@link MenuItem#getItemId() menu item id} matches a valid
     * {@link NavDestination#getAction(int) action id} or
     * {@link NavDestination#getId() destination id} to be navigated to.</p>
     * <p>
     * By default, the back stack will be popped back to the navigation graph's start destination.
     * Menu items that have <code>android:menuCategory="secondary"</code> will not pop the back
     * stack.
     *
     * @param item The selected MenuItem.
     * @param navController The NavController that hosts the destination.
     * @return True if the {@link NavController} was able to navigate to the destination
     * associated with the given MenuItem.
     */
    public static boolean onNavDestinationSelected(@NonNull MenuItem item,
            @NonNull NavController navController) {
        NavOptions.Builder builder = new NavOptions.Builder()
                .setLaunchSingleTop(true);
        if (navController.getCurrentDestination().getParent().findNode(item.getItemId())
                instanceof ActivityNavigator.Destination) {
            builder.setEnterAnim(R.anim.nav_default_enter_anim)
                    .setExitAnim(R.anim.nav_default_exit_anim)
                    .setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
                    .setPopExitAnim(R.anim.nav_default_pop_exit_anim);

        } else {
            builder.setEnterAnim(R.animator.nav_default_enter_anim)
                    .setExitAnim(R.animator.nav_default_exit_anim)
                    .setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
                    .setPopExitAnim(R.animator.nav_default_pop_exit_anim);
        }
        if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {
            builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false);
        }
        NavOptions options = builder.build();
        try {
            //TODO provide proper API instead of using Exceptions as Control-Flow.
            navController.navigate(item.getItemId(), null, options);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    /**
     * Handles the Up button by delegating its behavior to the given NavController. This should
     * generally be called from {@link AppCompatActivity#onSupportNavigateUp()}.
     * <p>If you do not have a {@link Openable} layout, you should call
     * {@link NavController#navigateUp()} directly.
     *
     * @param navController The NavController that hosts your content.
     * @param openableLayout The Openable layout that should be opened if you are on the topmost
     *                       level of the app.
     * @return True if the {@link NavController} was able to navigate up.
     */
    public static boolean navigateUp(@NonNull NavController navController,
            @Nullable Openable openableLayout) {
        return navigateUp(navController, new AppBarConfiguration.Builder(navController.getGraph())
                .setOpenableLayout(openableLayout)
                .build());
    }

    /**
     * Handles the Up button by delegating its behavior to the given NavController. This is
     * an alternative to using {@link NavController#navigateUp()} directly when the given
     * {@link AppBarConfiguration} needs to be considered when determining what should happen
     * when the Up button is pressed.
     * <p>
     * In cases where no Up action is available, the
     * {@link AppBarConfiguration#getFallbackOnNavigateUpListener()} will be called to provide
     * additional control.
     *
     * @param navController The NavController that hosts your content.
     * @param configuration Additional configuration options for determining what should happen
     *                      when the Up button is pressed.
     * @return True if the {@link NavController} was able to navigate up.
     */
    public static boolean navigateUp(@NonNull NavController navController,
            @NonNull AppBarConfiguration configuration) {
        Openable openableLayout = configuration.getOpenableLayout();
        NavDestination currentDestination = navController.getCurrentDestination();
        Set<Integer> topLevelDestinations = configuration.getTopLevelDestinations();
        if (openableLayout != null && currentDestination != null
                && matchDestinations(currentDestination, topLevelDestinations)) {
            openableLayout.open();
            return true;
        } else {
            if (navController.navigateUp()) {
                return true;
            } else if (configuration.getFallbackOnNavigateUpListener() != null) {
                return configuration.getFallbackOnNavigateUpListener().onNavigateUp();
            } else {
                return false;
            }
        }
    }

    /**
     * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use
     * with a {@link NavController}.
     *
     * <p>By calling this method, the title in the action bar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On all other destinations, the ActionBar will show the Up button.
     * Call {@link NavController#navigateUp()} to handle the Up button.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param activity The activity hosting the action bar that should be kept in sync with changes
     *                 to the NavController.
     * @param navController The NavController that supplies the secondary menu. Navigation actions
     *                      on this NavController will be reflected in the title of the action bar.
     * @see #setupActionBarWithNavController(AppCompatActivity, NavController, AppBarConfiguration)
     */
    public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity,
            @NonNull NavController navController) {
        setupActionBarWithNavController(activity, navController,
                new AppBarConfiguration.Builder(navController.getGraph())
                        .build());
    }

    /**
     * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use
     * with a {@link NavController}.
     *
     * <p>By calling this method, the title in the action bar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On the start destination of your navigation graph, the ActionBar will show
     * the drawer icon if the given Openable layout is non null. On all other destinations,
     * the ActionBar will show the Up button.
     * Call {@link #navigateUp(NavController, Openable)} to handle the Up button.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param activity The activity hosting the action bar that should be kept in sync with changes
     *                 to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the action bar.
     * @param openableLayout The Openable layout that should be toggled from the home button
     * @see #setupActionBarWithNavController(AppCompatActivity, NavController, AppBarConfiguration)
     */
    public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity,
            @NonNull NavController navController,
            @Nullable Openable openableLayout) {
        setupActionBarWithNavController(activity, navController,
                new AppBarConfiguration.Builder(navController.getGraph())
                        .setOpenableLayout(openableLayout)
                        .build());
    }

    /**
     * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use
     * with a {@link NavController}.
     *
     * <p>By calling this method, the title in the action bar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The {@link AppBarConfiguration} you provide controls how the Navigation button is
     * displayed.
     * Call {@link #navigateUp(NavController, AppBarConfiguration)} to handle the Up button.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     *  @param activity The activity hosting the action bar that should be kept in sync with changes
     *                 to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the action bar.
     * @param configuration Additional configuration options for customizing the behavior of the
     *                      ActionBar
     */
    public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity,
            @NonNull NavController navController,
            @NonNull AppBarConfiguration configuration) {
        navController.addOnDestinationChangedListener(
                new ActionBarOnDestinationChangedListener(activity, configuration));
    }

    /**
     * Sets up a {@link Toolbar} for use with a {@link NavController}.
     *
     * <p>By calling this method, the title in the Toolbar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On all other destinations, the Toolbar will show the Up button. This
     * method will call {@link NavController#navigateUp()} when the Navigation button
     * is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController that supplies the secondary menu. Navigation actions
     *                      on this NavController will be reflected in the title of the Toolbar.
     * @see #setupWithNavController(Toolbar, NavController, AppBarConfiguration)
     */
    public static void setupWithNavController(@NonNull Toolbar toolbar,
            @NonNull NavController navController) {
        setupWithNavController(toolbar, navController,
                new AppBarConfiguration.Builder(navController.getGraph()).build());
    }

    /**
     * Sets up a {@link Toolbar} for use with a {@link NavController}.
     *
     * <p>By calling this method, the title in the Toolbar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On the start destination of your navigation graph, the Toolbar will show
     * the drawer icon if the given Openable layout is non null. On all other destinations,
     * the Toolbar will show the Up button. This method will call
     * {@link #navigateUp(NavController, Openable)} when the Navigation button is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the Toolbar.
     * @param openableLayout The Openable layout that should be toggled from the Navigation button
     * @see #setupWithNavController(Toolbar, NavController, AppBarConfiguration)
     */
    public static void setupWithNavController(@NonNull Toolbar toolbar,
            @NonNull final NavController navController,
            @Nullable final Openable openableLayout) {
        setupWithNavController(toolbar, navController,
                new AppBarConfiguration.Builder(navController.getGraph())
                        .setOpenableLayout(openableLayout)
                        .build());
    }

    /**
     * Sets up a {@link Toolbar} for use with a {@link NavController}.
     *
     * <p>By calling this method, the title in the Toolbar will automatically be updated when
     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
     *
     * <p>The {@link AppBarConfiguration} you provide controls how the Navigation button is
     * displayed and what action is triggered when the Navigation button is tapped. This method
     * will call {@link #navigateUp(NavController, AppBarConfiguration)} when the Navigation button
     * is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the Toolbar.
     * @param configuration Additional configuration options for customizing the behavior of the
     *                      Toolbar
     */
    public static void setupWithNavController(@NonNull Toolbar toolbar,
            @NonNull final NavController navController,
            @NonNull final AppBarConfiguration configuration) {
        navController.addOnDestinationChangedListener(
                new ToolbarOnDestinationChangedListener(toolbar, configuration));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navigateUp(navController, configuration);
            }
        });
    }

    /**
     * Sets up a {@link CollapsingToolbarLayout} and {@link Toolbar} for use with a
     * {@link NavController}.
     *
     * <p>By calling this method, the title in the CollapsingToolbarLayout will automatically be
     * updated when the destination changes (assuming there is a valid
     * {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On all other destinations, the Toolbar will show the Up button. This
     * method will call {@link NavController#navigateUp()} when the Navigation button
     * is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param collapsingToolbarLayout The CollapsingToolbarLayout that should be kept in sync with
     *                                changes to the NavController.
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController that supplies the secondary menu. Navigation actions
     *                      on this NavController will be reflected in the title of the Toolbar.
     */
    public static void setupWithNavController(
            @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
            @NonNull Toolbar toolbar,
            @NonNull NavController navController) {
        setupWithNavController(collapsingToolbarLayout, toolbar, navController,
                new AppBarConfiguration.Builder(navController.getGraph()).build());
    }

    /**
     * Sets up a {@link CollapsingToolbarLayout} and {@link Toolbar} for use with a
     * {@link NavController}.
     *
     * <p>By calling this method, the title in the CollapsingToolbarLayout will automatically be
     * updated when the destination changes (assuming there is a valid
     * {@link NavDestination#getLabel label}).
     *
     * <p>The start destination of your navigation graph is considered the only top level
     * destination. On the start destination of your navigation graph, the Toolbar will show
     * the drawer icon if the given Openable layout is non null. On all other destinations,
     * the Toolbar will show the Up button. This method will call
     * {@link #navigateUp(NavController, Openable)} when the Navigation button is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param collapsingToolbarLayout The CollapsingToolbarLayout that should be kept in sync with
     *                                changes to the NavController.
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the Toolbar.
     * @param openableLayout The Openable layout that should be toggled from the Navigation button
     */
    public static void setupWithNavController(
            @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
            @NonNull Toolbar toolbar,
            @NonNull final NavController navController,
            @Nullable final Openable openableLayout) {
        setupWithNavController(collapsingToolbarLayout, toolbar, navController,
                new AppBarConfiguration.Builder(navController.getGraph())
                        .setOpenableLayout(openableLayout)
                        .build());
    }

    /**
     * Sets up a {@link CollapsingToolbarLayout} and {@link Toolbar} for use with a
     * {@link NavController}.
     *
     * <p>By calling this method, the title in the CollapsingToolbarLayout will automatically be
     * updated when the destination changes (assuming there is a valid
     * {@link NavDestination#getLabel label}).
     *
     * <p>The {@link AppBarConfiguration} you provide controls how the Navigation button is
     * displayed and what action is triggered when the Navigation button is tapped. This method
     * will call {@link #navigateUp(NavController, AppBarConfiguration)} when the Navigation button
     * is clicked.
     *
     * <p>Destinations that implement {@link androidx.navigation.FloatingWindow} will be ignored.
     *
     * @param collapsingToolbarLayout The CollapsingToolbarLayout that should be kept in sync with
     *                                changes to the NavController.
     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
     * @param navController The NavController whose navigation actions will be reflected
     *                      in the title of the Toolbar.
     * @param configuration Additional configuration options for customizing the behavior of the
     *                      Toolbar
     */
    public static void setupWithNavController(
            @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
            @NonNull Toolbar toolbar,
            @NonNull final NavController navController,
            @NonNull final AppBarConfiguration configuration) {
        navController.addOnDestinationChangedListener(
                new CollapsingToolbarOnDestinationChangedListener(
                        collapsingToolbarLayout, toolbar, configuration));
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navigateUp(navController, configuration);
            }
        });
    }

    /**
     * Sets up a {@link NavigationView} for use with a {@link NavController}. This will call
     * {@link #onNavDestinationSelected(MenuItem, NavController)} when a menu item is selected.
     * The selected item in the NavigationView will automatically be updated when the destination
     * changes.
     * <p>
     * If the {@link NavigationView} is directly contained with an {@link Openable} layout,
     * it will be closed when a menu item is selected.
     * <p>
     * Similarly, if the {@link NavigationView} has a {@link BottomSheetBehavior} associated with
     * it (as is the case when using a {@link com.google.android.material.bottomsheet.BottomSheetDialog}),
     * the bottom sheet will be hidden when a menu item is selected.
     *
     * @param navigationView The NavigationView that should be kept in sync with changes to the
     *                       NavController.
     * @param navController The NavController that supplies the primary and secondary menu.
     *                      Navigation actions on this NavController will be reflected in the
     *                      selected item in the NavigationView.
     */
    public static void setupWithNavController(@NonNull final NavigationView navigationView,
            @NonNull final NavController navController) {
        navigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        boolean handled = onNavDestinationSelected(item, navController);
                        if (handled) {
                            ViewParent parent = navigationView.getParent();
                            if (parent instanceof Openable) {
                                ((Openable) parent).close();
                            } else {
                                BottomSheetBehavior bottomSheetBehavior =
                                        findBottomSheetBehavior(navigationView);
                                if (bottomSheetBehavior != null) {
                                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
                                }
                            }
                        }
                        return handled;
                    }
                });
        final WeakReference<NavigationView> weakReference = new WeakReference<>(navigationView);
        navController.addOnDestinationChangedListener(
                new NavController.OnDestinationChangedListener() {
                    @Override
                    public void onDestinationChanged(@NonNull NavController controller,
                            @NonNull NavDestination destination, @Nullable Bundle arguments) {
                        NavigationView view = weakReference.get();
                        if (view == null) {
                            navController.removeOnDestinationChangedListener(this);
                            return;
                        }
                        Menu menu = view.getMenu();
                        for (int h = 0, size = menu.size(); h < size; h++) {
                            MenuItem item = menu.getItem(h);
                            item.setChecked(matchDestination(destination, item.getItemId()));
                        }
                    }
                });
    }

    /**
     * Walks up the view hierarchy, trying to determine if the given View is contained within
     * a bottom sheet.
     */
    @SuppressWarnings("WeakerAccess")
    static BottomSheetBehavior findBottomSheetBehavior(@NonNull View view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
            ViewParent parent = view.getParent();
            if (parent instanceof View) {
                return findBottomSheetBehavior((View) parent);
            }
            return null;
        }
        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
                .getBehavior();
        if (!(behavior instanceof BottomSheetBehavior)) {
            // We hit a CoordinatorLayout, but the View doesn't have the BottomSheetBehavior
            return null;
        }
        return (BottomSheetBehavior) behavior;
    }

    /**
     * Sets up a {@link BottomNavigationView} for use with a {@link NavController}. This will call
     * {@link #onNavDestinationSelected(MenuItem, NavController)} when a menu item is selected. The
     * selected item in the BottomNavigationView will automatically be updated when the destination
     * changes.
     *
     * @param bottomNavigationView The BottomNavigationView that should be kept in sync with
     *                             changes to the NavController.
     * @param navController The NavController that supplies the primary menu.
     *                      Navigation actions on this NavController will be reflected in the
     *                      selected item in the BottomNavigationView.
     */
    public static void setupWithNavController(
            @NonNull final BottomNavigationView bottomNavigationView,
            @NonNull final NavController navController) {
        bottomNavigationView.setOnNavigationItemSelectedListener(
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        return onNavDestinationSelected(item, navController);
                    }
                });
        final WeakReference<BottomNavigationView> weakReference =
                new WeakReference<>(bottomNavigationView);
        navController.addOnDestinationChangedListener(
                new NavController.OnDestinationChangedListener() {
                    @Override
                    public void onDestinationChanged(@NonNull NavController controller,
                            @NonNull NavDestination destination, @Nullable Bundle arguments) {
                        BottomNavigationView view = weakReference.get();
                        if (view == null) {
                            navController.removeOnDestinationChangedListener(this);
                            return;
                        }
                        Menu menu = view.getMenu();
                        for (int h = 0, size = menu.size(); h < size; h++) {
                            MenuItem item = menu.getItem(h);
                            if (matchDestination(destination, item.getItemId())) {
                                item.setChecked(true);
                            }
                        }
                    }
                });
    }

    /**
     * Determines whether the given <code>destId</code> matches the NavDestination. This handles
     * both the default case (the destination's id matches the given id) and the nested case where
     * the given id is a parent/grandparent/etc of the destination.
     */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    static boolean matchDestination(@NonNull NavDestination destination,
            @IdRes int destId) {
        NavDestination currentDestination = destination;
        while (currentDestination.getId() != destId && currentDestination.getParent() != null) {
            currentDestination = currentDestination.getParent();
        }
        return currentDestination.getId() == destId;
    }

    /**
     * Determines whether the given <code>destinationIds</code> match the NavDestination. This
     * handles both the default case (the destination's id is in the given ids) and the nested
     * case where the given ids is a parent/grandparent/etc of the destination.
     */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    static boolean matchDestinations(@NonNull NavDestination destination,
            @NonNull Set<Integer> destinationIds) {
        NavDestination currentDestination = destination;
        do {
            if (destinationIds.contains(currentDestination.getId())) {
                return true;
            }
            currentDestination = currentDestination.getParent();
        } while (currentDestination != null);
        return false;
    }

    /**
     * Finds the actual start destination of the graph, handling cases where the graph's starting
     * destination is itself a NavGraph.
     */
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    static NavDestination findStartDestination(@NonNull NavGraph graph) {
        NavDestination startDestination = graph;
        while (startDestination instanceof NavGraph) {
            NavGraph parent = (NavGraph) startDestination;
            startDestination = parent.findNode(parent.getStartDestination());
        }
        return startDestination;
    }
}