Question

I need to show a system overlay window on top of any running apps. It works fine, but only when my app's activity is in foreground. Here is the code I use:

params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
                    WindowManager.LayoutParams.FLAG_DIM_BEHIND |
                    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | 
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                    PixelFormat.TRANSLUCENT);

params.gravity = Gravity.CENTER | Gravity.TOP;
params.dimAmount = 0.3f;
wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);

    mainAlertView = View.inflate(ctx, R.layout.system_alert_view, null);

    wm.addView(mainAlertView, params);

The view added to WindowManager contains empty LinearLayout to which I add child views at runtime:

    mainAlertLayout.addView(childView);

Manifest xml has SYSTEM_ALERT_WINDOW permission defined:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

It all works magnificently while my activity is running in foreground. As soon as I switch to any other app or home screen no overlay is shown. I debugged the code, and it indeed is running wm.addView(), and its not throwing any exceptions. I also played around with LayoutParams flags (removed KEEP_SCREEN_ON and related etc), but nothing made any difference.

Android 4.4.2 fwiw

Was it helpful?

Solution 2

The problem was that I was running addView() call in main view's post() method:

mainView.post(new Runnable() {
 public void run() {
  wm.add(mainView);
 }
);

Instead if I just run it in main thread it works fine. I use de.greenrobot.eventbus and its very simple to post Runnable to event bus and ensure it executes in main thread:

public void onEventMainThread(UIRunnableEvent event) {
    event.r.run();
}

public static class UIRunnableEvent {
    protected Runnable r;

    protected UIRunnableEvent(Runnable r) {
        this.r = r;
    }
}

OTHER TIPS

You need to create a service to keep the system overlay( alert) to show even when your application closed.

Create a simple service , I will call as FloatingService , which will show the overlay(alert) when onStartCommand is called . Return START_STICKY to keep the service run in background.

    public class FloatingService extends Service {
      private WindowManager windowManager;
      private View floatingView;

     WindowManager.LayoutParams params;
    @Override
     public IBinder onBind(Intent intent) {
        return null;
      }

     @Override
     public int onStartCommand(Intent intent, int flag, int startId){
      // show the alert her
      windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
       // use your custom view here
        floatingView = View.inflate(getBaseContext(),R.layout.floating_layout,null);            //floatingView.setOnTouchListener(mOnTouchListener);
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                PixelFormat.TRANSLUCENT);
           params.gravity = Gravity.CENTER | Gravity.CENTER;
        // add the view to window manger
        windowManager.addView(floatingView, params);
      return START_STICKY;
     }
 }

Add an listener to the view so that you can close the overlay(alert) when required

      floatingView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                windowManager.removeView(floatingView);
                floatingView = null;
            }
        });

Finally , register the service in manifest

 <service android:name="com.example.app.services.FloatingService" />

And System Alert permission

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top