0

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.

Community
  • 1
  • 1
Denny
  • 1,766
  • 3
  • 17
  • 37

1 Answers1

2

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.

nandsito
  • 3,782
  • 2
  • 19
  • 26
  • Seems the reason for it. Although I've had a look at another app and they were able to achieve this using `TYPE_SYSTEM_ERROR` (see the update in the post and the gif) and there isn't another window type that displays the view on the lockscreen that includes interaction – Denny Apr 23 '17 at 19:01
  • And what do you mean with handling the view bounds in a stricter manner? Could you give an example? – Denny Apr 23 '17 at 23:43
  • @Denny that would probably be very laborious, but i thought of detecting if the view to be added would go beyond the screen limits. In other words, doing all the calculations before inserting the view to detect if the undesired behavior would happen, and then adjust the view layout so it doesn't happen. In sum, preventing the undesired behavior by adjusting the view layout – nandsito Apr 23 '17 at 23:55
  • Found an ugly workaround for this using padding and margin, it allows me to display the view partially when locked and still interact with it. Seems there's currently no other option for it. – Denny Apr 25 '17 at 09:39