Default layout
Base theme without action bar:
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
</style>
Set background color for status and navigation bars
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
<item name="android:statusBarColor">@android:color/holo_purple</item>
<item name="android:navigationBarColor">@android:color/holo_red_dark</item>
</style>
Make status and navigation bars transparent
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
Make status bar text color contrasted
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
...
</style>
windowLightStatusBar = true
-> status bar will be drawn compatible with a light background
Make the layout fit the screen edge-to-edge
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
}
Layout is letterboxed in landscape mode
This 'bug' is present even in Google products like Maps and Google Earth; Sky Map is even displayed in full cutout mode.
Make layout fit the screen edge-to-edge in landscape mode
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
...
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
windowLayoutInDisplayCutoutMode
can take one of three values:
default
: content renders into the cutout area when displayed in portrait mode, but is letterboxed when in landscape modeshortEdges
: content always renders into the cutout areanever
: content never renders into the cutout area
windowLayoutInDisplayCutoutMode
requires API level 27, so if your app supports lower API level, then extract it into "values-v27/themes.xml".
- values/themes.xml:
<style name="Base.Theme.ShortEdges" parent="Theme.Material3.Light.NoActionBar">
...
</style>
<style name="Theme.ShortEdges" parent="Base.Theme.ShortEdges" />
- values-v27/themes.xml:
<style name="Theme.ShortEdges" parent="Base.Theme.ShortEdges">
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
How to determine safe region
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.my_view), this::onApplyWindowInsets);
}
@NonNull
public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowInsetsCompat windowInsets) {
final Insets displayCutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
final Insets systemBarsInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
final Insets safeInsets = Insets.of(
max(displayCutoutInsets.left, systemBarsInsets.left),
max(displayCutoutInsets.top, systemBarsInsets.top),
max(displayCutoutInsets.right, systemBarsInsets.right),
max(displayCutoutInsets.bottom, systemBarsInsets.bottom)
);
return WindowInsetsCompat.CONSUMED;
}
Set component view margins
final ViewGroup.MarginLayoutParams mlp =
(ViewGroup.MarginLayoutParams) view.getLayoutParams();
mlp.leftMargin = safeInsets.left;
mlp.topMargin = safeInsets.top;
mlp.bottomMargin = safeInsets.bottom;
mlp.rightMargin = safeInsets.right;
view.setLayoutParams(mlp);
Resources
- GitHub: https://github.com/asilichenko/android-short-edges
- Display content edge-to-edge in your app: https://developer.android.com/develop/ui/views/layout/edge-to-edge
- Support display cutouts: https://developer.android.com/develop/ui/views/layout/display-cutout