在 android 中创建叠加层 window 19

Create an overlay window in android 19

我正在尝试在 android 中创建一个叠加层 window(即使我的应用程序在后台运行,它也会浮在屏幕上的任何其他应用程序之上)

我遵循了几个指南(一些来自 SO),这里是重要的代码

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);

我已经在 android 29 上测试过并且工作得很好
但是在 android 19 window 打开,但只要当前应用进入后台,window 就会打开。我希望 window 即使在用户切换应用程序后仍保持打开状态。

这就是我得到 19 的方式

这是 android 29(正确方式)
中的工作原理 https://i.imgur.com/JjMugfG.mp4

我做错了什么吗

问题是 Activity 中的 WindowManager 实例与 application-level Context 中检索到的实例不同。

我们来做个测试:

@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));
}

结果是FALSE.

实际上,一个WindowManager负责管理屏幕上windows的列表。在 Activities 的情况下,当 Activity 消失时,所有相关的 windows 都会消失,例如您添加的浮动视图。当您的应用程序在按下主页按钮后处于后台时,例如,它的 window 管理器(Application 的 window 管理器)保留所有托管的 windows。这意味着您的浮动视图有机会显示,直到应用程序被系统杀死。

因此,通过从 application-level Context 中检索 WindowManager 实例并向其添加视图,问题将得到解决。

您从 activity 获得的 window 管理器在添加视图时指出 Activity.getWindow(),如果您单击后退按钮或主页按钮,该视图自然会消失。这意味着您需要另一个装饰视图来解决您的问题,它在您的案例中调用应用程序上下文,它可以让您根据需要管理 phone 的 window。

检查应用程序上下文,如果它不为空,则获取 WindowManager 实例,然后尝试添加您的视图。

我也不确定,但使用 WindowManager.TYPE_SYSTEM_ALERT 也可能有帮助。

7 年来,我从事浮动应用程序 (https://floatingapps.net) 的工作,它基本上是一组浮动 mini-apps,所以我对此有所了解 :-)。

我首先在 Android 2.3.5 上开始工作,直到今天才开始工作。

如果您想在所有可能的设备和 Android 版本上正确执行此操作,这是一个复杂的问题。

我最近发表了一系列关于这个主题的文章。检查一下:https://localazy.com/blog/floating-windows-on-android-1-jetpack-compose-and-room

它从主应用程序、后台服务、权限、浮动 windows、移动它们、键盘输入到我在此过程中学到的提示、技巧和缺点列表。

它应该教你如何正确地做。