英文:
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论