Developer guide
Window insets in Compose and Views
Jetpack Compose
Compose is Android's recommended UI toolkit, so its examples come first. If your app still uses XML layouts, the View-based equivalents follow below.
In Compose, WindowInsets.safeDrawing is the union of systemBars, displayCutout and ime. With the keyboard hidden it equals the Safe Area Insets shown on each device page, so those values are what this padding resolves to on that model.
Opting in to edge-to-edge
Apps targeting Android 15 (API 35) are drawn edge-to-edge by default. Call enableEdgeToEdge() so older versions behave the same, then pad content yourself:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
setContent {
Box(
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface) // drawn behind the bars
.windowInsetsPadding(WindowInsets.safeDrawing) // or .safeDrawingPadding()
) {
Content()
}
}
}
}With Material 3 Scaffold
Scaffold places its bars inside the insets and hands the remaining space to the content as innerPadding. Pass contentWindowInsets explicitly so the cutout is included in landscape:
Scaffold(
topBar = { TopAppBar(title = { Text("Inbox") }) },
floatingActionButton = { FloatingActionButton(onClick = {}) { Icon(Icons.Default.Add, null) } },
contentWindowInsets = WindowInsets.safeDrawing,
) { innerPadding ->
LazyColumn(
modifier = Modifier.consumeWindowInsets(innerPadding),
contentPadding = innerPadding, // list scrolls behind the bars, last item stays reachable
) {
items(messages) { MessageRow(it) }
}
}Picking the right inset type
safeDrawing: keep text and images from being covered by bars, the cutout or the keyboard.safeGestures: keep draggable controls out of the system gesture zones.safeContent: both of the above, for content that is visible and interactive.displayCutoutalone: full-bleed media that only needs to avoid the camera.
Reading the values
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val safe = WindowInsets.safeDrawing
val topPx = safe.getTop(density) // Int, px
val padding = safe.asPaddingValues() // PaddingValues, dp
val startDp = padding.calculateStartPadding(layoutDirection)Views: reading insets in your Activity or Fragment
With ViewCompat (Jetpack, recommended)
Use ViewCompat.setOnApplyWindowInsetsListener:
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
val statusBars = insets.getInsets(Type.statusBars())
val navBars = insets.getInsets(Type.navigationBars())
val cutout = insets.getInsets(Type.displayCutout())
// Apply padding: view.setPadding(
// statusBars.left, statusBars.top,
// statusBars.right, navBars.bottom
// )
insets // return unhandled insets to others
}Direct API access
On API 29+, use WindowInsets.getInsets(). On newer APIs (31+), also check Display.getRoundedCorner().
Views: safe areas for content
Safe area = system bars + display cutout. Combine them to find where content is always visible and tappable:
val systemBars = insets.getInsets(Type.systemBars())
val cutout = insets.getInsets(Type.displayCutout())
val safe = Insets.of(
max(systemBars.left, cutout.left),
max(systemBars.top, cutout.top),
max(systemBars.right, cutout.right),
max(systemBars.bottom, cutout.bottom)
)Found an issue or want to contribute?
Open an issue or pull request on GitHub. If you have a device and want to add insets data, use InsetsProbe and share your JSON.