Beginning with Android 10 (API level 29), the Android system supports fully gesture-based navigation. There are two things that app developers should do to ensure their apps are compatible with this feature:
- Extend app content from edge to edge.
- Handle conflicting app gestures.
Edge-to-edge app content
In order to take advantage of the additional screen space made available by the floating navigation bar, you'll need to make some changes to your app.
Setting transparent system bars
You can do this by setting the following values in your theme:
<!-- values-29/themes.xml: -->
<style name="AppTheme" parent="...">
<item name="android:navigationBarColor">@android:color/transparent</item>
<!-- Optional, but recommended for full edge-to-edge rendering -->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>

Alternatively, you can do this dynamically by using
Window.setNavigationBarColor()
and Window.setStatusBarColor()
.
When the device is set use gesture navigation, and you make the background of your app's navigation bar transparent, the system automatically updates the color of the handle based on the color of the content behind it. However, when the user is in 2-button or 3-button navigation mode, these buttons don't change color. Instead, the system applies a translucent background so the buttons stay visible. However, the system can only do this if the app targets API level 29 or higher.
Setting UI visibility flag
To be able to lay out your view edge-to-edge, your app must tell the system that
the app can handle such a view. You can accomplish this using
View.setSystemUiVisibility()
to set the following flags:
Kotlin
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
Java
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
Together, these flags tell the system that your app should be laid out
fullscreen, and as if the navigation and status bars were not there. For
additional full-screen events, you can also set
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
,
which allows you to draw behind the status bar.
If you are using a view class such as CoordinatorLayout
or DrawerLayout
that automatically handles the status bar, the SYSTEM_UI_FLAG_LAYOUT_STABLE
and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
flags may already be set. Also, if you
are using setSystemUiVisibility()
to set other flags, such as
SYSTEM_UI_FLAG_IMMERSIVE
, you should be
careful that those other flags don't overwrite the ones referenced above.
Even if your app uses an edge-to-edge view, the system still uses the
WindowInsets
API to indicate where the
system bars are.
Consuming insets manually
If your app uses a custom view hierarchy, you may need to consume system window
insets manually. You typically do this by implementing an
OnApplyWindowInsetsListener
interface:
Kotlin
view.setOnApplyWindowInsetsListener() {v, insets -> insets.consumeSystemWindowInsets()
Java
view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @Override public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { // 1. Move views on top edge down by insets.getSystemWindowInsetTop() // 2. Move views on bottom edge up by insets.getSystemWindowInsetBottom() // 3. Also check getSystemWindowInsetLeft/Right(), such as for landscape // orientations return insets.consumeSystemWindowInsets(); } });
WindowInsets
provides regular visual
insets for all system bars through getSystemWindowInsets()
. In
addition, Android 10 adds the following methods to WindowInsets
:
getSystemGestureInsets()
: Indicates the size of the region where system gestures are captured.getMandatorySystemGestureInsets()
: Same as above, but only indicates regions that cannot be overridden byView.setSystemGestureExclusionRects()
.
Handling conflicting app gestures
The gesture navigation model may conflict with gestures that were previously used by app developers. You may need to make adjustments to your app's user interface as a result.
Conflicts with Back gestures
The new system gesture for Back is an inward swipe from either the left or the
right edge of the screen. This may interfere with app navigation elements in
those areas. To maintain functionality of elements on the left and right edges
of the screen, you'll need to opt out of the Back gesture selectively by
indicating to the system which regions need to receive touch input. You can do
this by passing a List<Rect>
to the View.setSystemGestureExclusionRects()
API introduced in Android 10. This method is also available in ViewCompat
as of
androidx.core:core:1.1.0-dev01
.
For example:
Kotlin
var exclusionRects = listOf(rect1, rect2, rect3) fun onLayout( changedCanvas: Boolean, left: Int, top: Int, right: Int, bottom: Int) { // Update rect bounds and the exclusionRects list setSystemGestureExclusionRects(exclusionRects) } fun onDraw(canvas: Canvas) { // Update rect bounds and the exclusionRects list setSystemGestureExclusionRects(exclusionRects) }
Java
List<Rect> exclusionRects; public void onLayout( boolean changedCanvas, int left, int top, int right, int bottom) { // Update rect bounds and the exclusionRects list setSystemGestureExclusionRects(exclusionRects); } public void onDraw(Canvas canvas) { // Update rect bounds and the exclusionRects list setSystemGestureExclusionRects(exclusionRects); }
Conflicts with Home/Quick Switch gestures
The new system gestures for Home and Quick Switch both involve swipes at the bottom of the screen in the space previously occupied by the nav bar. Apps cannot opt out of these gestures, as they can with the Back gesture.
To mitigate this problem, Android 10 introduces the
WindowInsets.getMandatorySystemGestureInsets()
API, which informs apps of the touch recognition thresholds.
Games and other non-View apps
Games and other apps that don't have a view hierarchy often require the user to
swipe near the system gesture areas. In those cases, games can use
Window.setSystemGestureExclusionRects()
to exclude areas that overlap with areas reserved for system gestures. Games
should make sure to only exclude these areas when necessary, such as during
gameplay.
If a game requires the user to swipe near the home gesture area, the app can request to be laid out in immersive mode. This disables the system gestures while the user is interacting with the game, but allows the user to re-enable the system gestures by swiping from the bottom of the screen.
Additional resources
To learn more about gesture navigation, consult the following additional resources.
Blog posts
Videos
- Android 10 - Gesture navigation
- Dark theme and gesture navigation - Google I/O ’19
- Android 10 - Edge to edge apps