javaandroidandroid-windowmanager

Create an overlay window in android 19


I'm trying to create an overlay window in android (a which will float over any other app in the screen, even when my app is on background)

I followed several guides (some from SO) and here is the important code

this.sp = PreferenceManager.getDefaultSharedPreferences(context);
        this.wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

         
        this.main = (FrameLayout) LayoutInflater.from(c).inflate(R.layout.ui_floating_window, null);
        

        int type = WindowManager.LayoutParams.TYPE_TOAST;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
            type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

        Point p = new Point();
        wm.getDefaultDisplay().getSize(p);
        this.displayHeight = p.y;
        this.displayWidth = p.x;
        this.rationWH = this.displayWidth / (float) this.displayHeight;
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                sp.getInt(Constants.DefaultSharedPreferences.FLOATING_WINDOW_WIDTH, this.displayWidth / 2),
                sp.getInt(Constants.DefaultSharedPreferences.FLOATING_WINDOW_HEIGHT, this.displayHeight / 2),
                sp.getInt(Constants.DefaultSharedPreferences.FLOATING_WINDOW_X, this.displayWidth / 2),
                sp.getInt(Constants.DefaultSharedPreferences.FLOATING_WINDOW_Y, this.displayHeight / 2),
                type,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.START | Gravity.TOP;
        params.horizontalMargin = 0;
        params.verticalMargin = 0;

        this.wm.addView(main, params);

i've tested on android 29 and works really fine
but on android 19 the window opens but as soon as the current app goes background the window goes either. i would like the window stayed on even after user switches the app.

This is how i get 19 asdasd

this is how it works in android 29 (correct way)
https://i.imgur.com/JjMugfG.mp4

am i doing anything wrong


Solution

  • The problem is that the WindowManager instance from Activity is different than the instance retrieved from the application-level Context.

    Let's try a test:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        Context context = this; // context of the activity
    
        WindowManager wm1 = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        WindowManager wm2 = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
    
        System.out.println("Are equal? " + wm1.equals(wm2));
    }
    

    The result is FALSE.

    Actually, a WindowManager is responsible for managing a list of windows on the screen. In the case of Activities, when the Activity gets disappeared, all of the related windows such as your added floating view would be gone. While your app lives in the background after pressing the home button, for instance, its window manager (Application's window manager) keeps all of the managed windows. It means that your floating view has the chance of being shown until the app would be killed by the system.

    So, by retrieving WindowManager instance from application-level Context and adding the view to it, the problem will be solved.