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 it works in android 29 (correct way)
https://i.imgur.com/JjMugfG.mp4
am i doing anything wrong
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.