粘性是指不会通过调用启动器意图(intent.addCategory(Intent.CATEGORY_HOME
)关闭的窗口。
以前,此操作是通过WindowManager.LayoutParams.TYPE_PHONE
完成的,但是现在不建议使用此类型,并且会在api 28上引发异常:
WindowManager $ BadTokenException ...窗口类型2002的权限被拒绝
基于Facebook的Messenger在其聊天“ Heads”中进行聊天的行为仍然可能,因为假设Facebook由于已预先安装在许多rom上而没有获得系统应用程序许可。
使用WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
不起作用(即,按下主屏幕按钮也会隐藏叠加窗口)。
编辑:问题是当用户单击“主页”按钮/调用启动器意图时,如何将其覆盖窗口移除。 TYPE_APPLICATION_OVERLAY
不是这种情况,TYPE_PHONE
是这种情况,但已过时。
编辑2:显然,这确实适用于某些人,这是我正在运行的代码:
class MyClass {
var params: WindowManager.LayoutParams = WindowManager.LayoutParams(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
else WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
).apply {
windowAnimations = android.R.style.Animation_Dialog
gravity = Gravity.CENTER or Gravity.CENTER
x = 0
y = 0
}
var windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
init {
val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
rootView = layoutInflater.inflate(R.layout.view_overlay, null)
windowManager.addView(rootView, params)
}
}
答案 0 :(得分:1)
Ref:https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html
TYPE_PHONE
public static final int TYPE_APPLICATION_OVERLAY
在API级别26中不推荐使用此常数。
用于非系统应用程序。请改用TYPE_APPLICATION_OVERLAY。
窗口类型:电话。 These are non-application windows providing user interaction with the phone
(尤其是来电)。这些窗口通常位于所有应用程序的上方,但位于状态栏的后面。在多用户系统中,所有用户的窗口上都会显示。
TYPE_APPLICATION_OVERLAY
public static final int TYPE_APPLICATION_OVERLAY
窗口类型:应用程序覆盖窗口显示在所有活动窗口上方(FIRST_APPLICATION_WINDOW
和LAST_APPLICATION_WINDOW
之间的类型),但显示在状态栏或IME之类的关键系统窗口下方。
系统可以随时更改这些窗口的位置,大小或可见性,以减少用户的视觉混乱并管理资源。
需要Manifest.permission.SYSTEM_ALERT_WINDOW
权限。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
系统将调整这种窗口类型的进程的重要性,以减少低内存杀手杀死它们的机会。
在多用户系统中,仅在拥有用户的屏幕上显示。
我们必须在设备Oreo或更高版本上使用TYPE APPLICATION OVERLAY 我们已经有 Manoj Perumarath 给出的示例
您需要定义这样的windowlayout参数
//if device is Oreo or latter if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//or else
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
Manifest.xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
//...other stuff
<service
android:name=".serviceClass"
android:enabled="true"
android:exported="false"/>
MainActivity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, APP_PERMISSION_REQUEST);
}
else
{
//start service
}
阅读一次
答案 1 :(得分:0)
在Manifest
中添加权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
在启动器活动中,您应该请求canDrawOverlays
权限`
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
!Settings.canDrawOverlays(this)) {
//If the draw over permission is not available open the settings screen
//to grant the permission.
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
} else {
initializeView();
}
然后在您的服务中
//Inflate the floating view layout
mFloatingView =
LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null);
int LAYOUT_TYPE;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_PHONE;
}
//Add the view to the window.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG ,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//Specify the view position
params.gravity = Gravity.TOP | Gravity.LEFT; //Initially view will be added to top-left corner
params.x = 0;
params.y = 100;
//Add the view to the window
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mFloatingView, params);
这不会随着用户按Home
键而消失。
请确保将浮动窗口小部件定义为service
,否则在内存不足/配置更改等问题时它将无法生存。
同时在清单中注册服务
<service
android:name=".MyWidget"
android:enabled="true"
android:exported="false"/>
答案 2 :(得分:0)
解决方案::请勿直接在其他应用程序上覆盖叠加层。
通常,使用TYPE_APPLICATION_OVERLAY
的行为仍然与TYPE_PHONE
相同,我的案例的问题在于,当来自另一个应用程序的活动位于前台时,我正在显示我的视图(windowManager.addView(rootView, params)
),并且Android将视图附加到当前的前台活动,因此,当用户退出该活动时(例如,通过按下主屏幕按钮),系统也会杀死我的应用中的叠加层。对我来说,解决方案非常具体,我没有一般性的解决方案,但是有了此信息,人们应该可以找到解决方案。