What is the proper way to use safe inset to survive notch hell on android devices?

276 Views Asked by At

I am trying to set safe inset in the activity as below:

@RequiresApi(Build.VERSION_CODES.Q)
override fun onAttachedToWindow() {
    super.onAttachedToWindow()

    val cutout = window.decorView.rootWindowInsets?.displayCutout
   
    cutout?.safeInsetTop
    cutout?.safeInsetBottom
    cutout?.safeInsetLeft
    cutout?.safeInsetRight

}

However I seem not to see any effect, meaning am implementing safe inset wrongly. I have not been able to come across a proper documentation on how to implement safe inset. Any help on how to do it on android is highly appreciated.

2

There are 2 best solutions below

0
On

You can set the cutout mode by setting a style in your project & there by survive the notch hell,

<style name="Theme.DeviceCompatability" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="android:windowLayoutInDisplayCutoutMode">never</item>
</style>

for more information, read here

0
On

For anyone looking for overall solution here is a custom View I made which calculate the offset from cutout as well from system decorations

Explanation

The magic happens on fitSystemWindows() with param insets provides safe offset of physical cutout height + system decoration height

the class file,

public class InsetSafeLinearLayout extends LinearLayout {
private final int defaultPadding;

private enum InsetOrientation {
    TOP,
    BOTTOM
}

private final InsetOrientation orientation;

private int calculatePadding(int systemInset) {
    return systemInset + Math.min(defaultPadding, Math.abs(systemInset - defaultPadding));
}

public InsetSafeLinearLayout(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray = getContext()
            .obtainStyledAttributes(attrs, R.styleable.InsetSafeLinearLayout);

    int enumIndex = typedArray.getInt(R.styleable.InsetSafeLinearLayout_placement, 0);
    orientation = InsetOrientation.values()[enumIndex];
    if (orientation == InsetOrientation.BOTTOM)
        defaultPadding = getPaddingBottom();
    else defaultPadding = getPaddingTop();
    typedArray.recycle();
}

@Override
protected boolean fitSystemWindows(Rect insets) {
    if (orientation == InsetOrientation.BOTTOM) {
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), calculatePadding(insets.bottom));
    } else {
        setPadding(getPaddingLeft(), calculatePadding(insets.top), getPaddingRight(), getPaddingBottom());
    }
    return false;
}
}

In styles.xml,

<declare-styleable name="InsetSafeLinearLayout">
    <attr name="placement" format="enum">
        <enum name="top" value="0" />
        <enum name="bottom" value="1" />
    </attr>
</declare-styleable>

It works pretty well for me it will gracefully calculate the extra padding to be added on LinearLayout placed either top or bottom on screen.