plaid icon indicating copy to clipboard operation
plaid copied to clipboard

Wrong WindowInsets after navigating from multi-window to single-window

Open azizbekian opened this issue 8 years ago • 1 comments

Assuming it is multi-window mode, where first app is an arbitrary app and second app is Plaid, then as soon as Plaid becomes the only app in foreground (mode changes to single-window), then Plaid gets wrong WindowInsets, which results toolbar not being correctly padded.

ezgif-5-fc533d73b8

Note, had Plaid been the first app (in the top of the screen), then WindowInsets are correctly dispatched.

Thoughts to workaround

If inside onApplyWindowInsets() checked:

drawer.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
    @Override
    public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
        if (insets.getSystemWindowInsetLeft() == 0 &&
                insets.getSystemWindowInsetTop() == 0 &&
                insets.getSystemWindowInsetRight() == 0 &&
                insets.getSystemWindowInsetBottom() == 0) {
            ViewCompat.requestApplyInsets(drawer);
            return insets.consumeSystemWindowInsets();
        }
        ...
    }
});

This will solve the issue, but the side effect is, that this will result in an infinite loop in multi-window mode, because those insets are 0 in multi-window mode, which is ok. Thus, we should check whether we are in multi- or single-window mode:

if (!isInMultiWindowMode() &&
        insets.getSystemWindowInsetLeft() == 0 &&
        insets.getSystemWindowInsetTop() == 0 &&
        insets.getSystemWindowInsetRight() == 0 &&
        insets.getSystemWindowInsetBottom() == 0) {
	
	    ViewCompat.requestApplyInsets(drawer);
	    return insets.consumeSystemWindowInsets();
}

If we are in a single-window mode and insets are equal to 0, only then request for a new dispatch.

Theoretically, this should work. In practice isInMultiWindowMode() still returns true when in single-window mode. Stale value issue of isInMultiWindowMode() is described in CommonsBlog.

On my machine 250ms is the delay, that is needed for the value to reflect real multi-window state. Following piece of code would make WindowInsets correctly applied:

@Override
public WindowInsets onApplyWindowInsets(View v, final WindowInsets insets) {

    if (isInMultiWindowMode()) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (!isInMultiWindowMode() && insets.getSystemWindowInsetLeft() == 0 &&
                        insets.getSystemWindowInsetTop() == 0 &&
                        insets.getSystemWindowInsetRight() == 0 &&
                        insets.getSystemWindowInsetBottom() == 0) {
                    ViewCompat.requestApplyInsets(drawer);
                }
            }
        }, 250);
        return insets.consumeSystemWindowInsets();
    }
    ...
}

azizbekian avatar Dec 18 '17 18:12 azizbekian

Chiming in here as the issue is still pervading the current implementation and can be quite unnerving when using multi-window mode. I studied the issue and i came up with the solution which i think is most elegant and doesn’t require listeners “racing” with each other and setting special timings (not a fan of those). As a “side-effect” it happens to clean up the code a bit as well in HomeActivity as well.

Solution re-uses already existing (in the core module utils) BindingAdapters as advocated by @chrisbanes (https://chris.banes.dev/2019/04/12/insets-listeners-to-layouts/) and - to my surprise used in other parts of codebase but not here - which i suspect might be just simply legacy code. Apart from issue described by @azizbekian there were also few others layout rendering problems i stumbled upon (see attached screenshot) and which are remedied by the PR #837 i’ve already provided.

/cc @nickbutcher

plaid-multi-window-bug

radekkozak avatar Jul 19 '20 11:07 radekkozak