在Android 19中创建一个叠加窗口。

huangapple go评论141阅读模式
英文:

Create an overlay window in android 19

问题

我正在尝试在 Android 中创建一个覆盖窗口(即浮动在屏幕上的任何其他应用程序上方的窗口,即使我的应用程序在后台运行)。

我按照几个指南(包括一些来自 Stack Overflow 的指南)进行操作,以下是关键代码:

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 上,窗口会在当前应用程序进入后台后关闭。我希望窗口在用户切换应用程序后仍然保持打开。

这是我在 Android 19 上的情况:

这是在 Android 29 上的工作方式(正确的方式):

我是否做错了什么?

英文:

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
在Android 19中创建一个叠加窗口。

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

am i doing anything wrong

答案1

得分: 2

问题在于来自“Activity”的“WindowManager”实例与从应用程序级别的“Context”检索到的实例不同。

让我们进行一次测试:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Context context = this; // 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负责管理屏幕上的窗口列表。对于“Activities”,当“Activity”消失时,所有相关的窗口,如您添加的浮动视图,都将消失。而当您按下主页按钮后,应用程序在后台运行时,其窗口管理器(Application的窗口管理器)会保留所有受管理的窗口。这意味着您的浮动视图有机会显示,直到应用程序被系统终止。

因此,通过从应用程序级别的“Context”检索“WindowManager”实例并将视图添加到其中,问题将得到解决。

英文:

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.

答案2

得分: 0

以下是翻译好的部分:

在过去的7年里,我一直在开发Floating Apps(https://floatingapps.net),它基本上是一组浮动的迷你应用程序,所以我对此有一些了解 :-).

我首次使其在Android 2.3.5上运行,并持续进行至今。

如果你想在所有可能的设备和Android版本上正确实现它,这是一个复杂的问题。

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

从主应用程序、后台服务、权限、浮动窗口、移动它们、键盘输入到我在开发过程中学到的提示、技巧和缺点列表,都有涉及。

它应该会教你如何正确实现它。

英文:

For 7 years, I work on Floating Apps (https://floatingapps.net) which is basically a set of floating mini-apps, so I know something about it :-).

I first get it working on Android 2.3.5 and progress until today.

It's a complex problem if you want to do it right across all possible devices and Android versions.

I recently published a series of articles on this topic. Check it out: https://localazy.com/blog/floating-windows-on-android-1-jetpack-compose-and-room

It goes from the main app, background service, permissions, floating windows, moving them, keyboard input to the list of tips, trick and shortcomings I learned along the way.

It should learn you how to do it right.

答案3

得分: -1

从活动中获取的窗口管理器指向 Activity.getWindow(),当添加视图时,如果点击返回按钮或主页按钮,视图自然会消失。这意味着您需要另一个装饰视图来解决您的问题,在您的情况下会调用应用程序上下文,从而允许您按照您的意愿管理手机的窗口。

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

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

英文:

The window manager you are getting from an activity points out to Activity.getWindow() when adding a view, which naturally disappears if you click the back button or home button. That means you need another decor view to resolve your problem, which is calling the application context in your case, where it will let you manage the phone's window, as you want.

Check application context, and if it's not null, get the WindowManager instance, then try adding your view.

Also I'm not sure but using WindowManager.TYPE_SYSTEM_ALERT also might help.

huangapple
  • 本文由 发表于 2020年9月12日 22:21:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/63861291.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定