Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw over navigation bar (and other apps) on Android version >= 5

I'd like to draw a (mouse pointer) icon on screen over the other applications from a service. I have implemented the functionality and I can draw over the screen, apart from the navigation bar. I've researched several other questions here and tried TYPE_SYSTEM_OVERLAY, TYPE_TOAST, TYPE_SYSTEM_ERROR and some other window types without success.

I'm not trying to capture focus, just drawing a mouse pointer on the screen for a second or two. When I try to draw over navigation bar, it just goes under (actually, the RelativeLayout ends on the border with navigation bar - even when I specify manual dimension for height). The screenshot below shows the hand pointer in the lower right part of the screen. That's as low as I can position it. Note that I'm not trying to hide the navigation bar in my application - trying to draw over other apps.

overlay-pointer-on-screen

I even tried setting the xpos and ypos offset settings in WindowManager.LayoutParams instance, but that just offsets the layout and still goes below the navigation bar).

The layout params I'm using to show this window:

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                PixelFormat.TRANSPARENT);

I am then adding the RelativeLayout with those parameters to the WindowManager: windowManager.addView(relativeLayout, params);

like image 932
miha Avatar asked Jul 20 '15 12:07

miha


2 Answers

The navigation bar at the bottom is something that cannot be drawn over because the items drawn above might impede access to the home button, back button, etc. But you can make your activity full-screen, meaning that it will hide the navigation buttons until you swipe up from the bottom, so that you can be free to draw anywhere on the screen

EDIT: I found some similar questions and this one has an answer : Draw bitmaps on top of the Navigation bar in Android The answer was to add a y offset that's the size of the navigation bar.

like image 65
LonelyIdiot Avatar answered Sep 20 '22 14:09

LonelyIdiot


After a lot of fiddling, I've managed to get the right flags to make it work. It almost works (for most apps). The code to achieve follows (an example on button click handler):

@Override
public void onClick(View view) {
    if (_windowManager == null) {
        _windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE);
    }

    WindowManager.LayoutParams params;
    // create the view on the first try
    if (_overlayView == null) {
        ImageView hand;

        _overlayView = new FrameLayout(MainActivity.this);
        hand = new ImageView(MainActivity.this);
        hand.setImageResource(R.drawable.icon_hand_pointer);
        int w = hand.getDrawable().getIntrinsicWidth();
        int h = hand.getDrawable().getIntrinsicHeight();
        _overlayView.addView(hand);

        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_FULLSCREEN |
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT);

        params.width = w;
        params.height = h;
        params.gravity = Gravity.LEFT | Gravity.TOP;
        params.x = _xOffset;
        params.y = _yOffset;
        _windowManager.addView(_overlayView, params);
    } else {
        // move the view
        params = (WindowManager.LayoutParams) _overlayView.getLayoutParams();
        params.x = _xOffset;
        params.y = _yOffset;
        _windowManager.removeView(_overlayView);
        _overlayView.setLayoutParams(params);
        _windowManager.addView(_overlayView, params);
    }

    _xOffset += 40;
    _yOffset += 100;
}

Here is a screenshot of this code working in an app (you can see the hand overlay; this is on Nexus 5 with Android 6.0.1: enter image description here

like image 45
miha Avatar answered Sep 19 '22 14:09

miha