Denny
Denny

Reputation: 1783

Flag WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS does not work with type WindowManager.LayoutParams.TYPE_SYSTEM_ERROR

I'm trying to display a view on the lockscreen and also want to be able to display it partially (eg. half of the view is off-screen when it's 'inactive').
With the type WindowManager.LayoutParams.TYPE_SYSTEM_ERROR as described here and here (and some other posts suggesting to use this flag), I am able to show it on the lockscreen. But together with the flag WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS doesn't seem to work on API level 21.

Code:

WindowManager.LayoutParams params = new 
    WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, 
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
    WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | 
    WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSPARENT);

But after some testing, the combination of the type WindowManager.LayoutParams.TYPE_SYSTEM_ERROR and the flag WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS does work on Android API level 16 but not on level 21. It just stays one side of an edge without going off-screen. I also tried setting the horizontalmargin property but to no avail.

Different results:

API level 16 (working)

API level 21 (not working)

Code for adding the view (stripped down):

layout = (RelativeLayout) getLayoutInflater().inflate(R.layout.testlayout, null).findViewById(R.id.rl);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSPARENT);
params.x = 600;
manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
manager.addView(layout, params);

Is this a bug or something else? Is there a workaround of this, if there is any?

Q&A:

do these two screens have the same dimensions, resolution, and density?

Resolution yes, dimensions no, and density also no.

if you increase the horizontal offset (the params.x value) a little, do both apis 16 and 21 go right?

On API level 16 it goes to the right a little, but on 21 it just stays on the right and does nothing.

UPDATE

I've had a look at another app and they were able to achieve this (see this gif). I decompiled their apk to have a look at their source code and the only method I've found regarding LayoutParams was:

private LayoutParams getLayoutParams() {
    LayoutParams params = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, this.lockscreen ? 2010 : 2002, 262696, -3);
    if (this.focusable) {
        params.flags ^= 8;
    }
    params.gravity = 8388659;
    if (this.keyboard) {
        params.softInputMode = 16;
    }
    return params;
}

this.lockscreen is a boolean whether it should display on the lockscreen

2010 is WindowManager.LayoutParams.TYPE_SYSTEM_ERROR (https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#TYPE_SYSTEM_ERROR)

2002 is WindowManager.LayoutParams.TYPE_PHONE, tried this and does not work on lockscreen(https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#TYPE_PHONE)

262696flags = 0x40228 = FLAG_WATCH_OUTSIDE_TOUCH, FLAG_LAYOUT_NO_LIMITS, FLAG_NOT_TOUCH_MODAL, FLAG_NOT_FOCUSABLE

-3 is PixelFormat.TRANSLUCENT (https://developer.android.com/reference/android/graphics/PixelFormat.html#TRANSLUCENT)

So I actually wonder how they achieved this because they also seem to use the type WindowManager.LayoutParams.TYPE_SYSTEM_ERROR.

Upvotes: 0

Views: 4526

Answers (1)

nandsito
nandsito

Reputation: 3852

That may not be possible...

I found this blog post:

In Android 4.4 this behavior was changed. Effectively, this change disables FLAG_LAYOUT_NO_LIMITS for TYPE_SYSTEM_ERROR Windows. This makes it impossible for user apps to place a Window over the shown navigation bar anymore.

which references this Android source code commit. The commit message states:

Limit TYPE_SYSTEM_ERROR to system decor bounds.

Because windows of TYPE_SYTEM_ERROR lie in a layer above the
Navigation Bar they cannot be allowed to extend into the Navigation
Bar area or it will block touches to the Home button.

Fixes bug 9626315

and a piece of diff shows:

- if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
+ // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+ if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {

On API 19 onwards you'll have to find another way. Maybe another window type, or handling the view bounds in a stricter manner.

Upvotes: 2

Related Questions