刚开始接触悬浮窗,看到网上有很多关于各个type 的介绍,但是没有具体说明它们之间的z轴顺序,所以特意做了调查。
一、含义:
首先先贴上各个type 的意义
应用程序窗口。 public static final int FIRST_APPLICATION_WINDOW = 1; 所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。 public static final int TYPE_BASE_APPLICATION =1; 普通应用功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。 public static final int TYPE_APPLICATION = 2; 用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。 它用于让系统显示些信息,直到应用程序可以开启自己的窗口。 public static final int TYPE_APPLICATION_STARTING = 3; 应用程序窗口结束。 public static final int LAST_APPLICATION_WINDOW = 99; 子窗口。子窗口的Z序和坐标空间都依赖于他们的宿主窗口。 public static final int FIRST_SUB_WINDOW = 1000; 面板窗口,显示于宿主窗口上层。 public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW; 媒体窗口,例如视频。显示于宿主窗口下层。 public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1; 应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上) public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2; 对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。 public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3; 媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕) public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW +4; 子窗口结束。( End of types of sub-windows ) public static final int LAST_SUB_WINDOW = 1999; 系统窗口。非应用程序创建。 public static final int FIRST_SYSTEM_WINDOW = 2000; 状态栏。只能有一个状态栏;它位于屏幕顶端,其他窗口都位于它下方。 public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW; 搜索栏。只能有一个搜索栏;它位于屏幕上方。 public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1; 电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。 public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2; 系统提示。它总是出现在应用程序窗口之上。 public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW +3; 锁屏窗口。 public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW +4; 信息窗口。用于显示toast。 public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW +5; 系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。 public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW +6; 电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。 public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW +7; 系统对话框。(例如音量调节框)。 public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW +8; 锁屏时显示的对话框。 public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW +9; 系统内部错误提示,显示于所有内容之上。 public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW +10; 内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。 public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW +11; 内部输入法对话框,显示于当前输入法窗口之上。 public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW +12; 墙纸窗口。 public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW +13; 状态栏的滑动面板。 public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW +14; 系统窗口结束。 public static final int LAST_SYSTEM_WINDOW = 2999;
以上为转载:http://realgodo.iteye.com/blog/1780176
二、层级:
对于不同的type系统的层级处理代码:
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return 2;
}
switch (type) {
case TYPE_UNIVERSE_BACKGROUND:
return 1;
case TYPE_PRIVATE_PRESENTATION:
return 2;
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 2;
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
case TYPE_RECENTS_OVERLAY:
case TYPE_SYSTEM_DIALOG:
return 5;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 6;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 7;
case TYPE_DREAM:
// used for Dreams (screensavers with TYPE_DREAM windows)
return 8;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
return 9;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 10;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 11;
case TYPE_KEYGUARD_SCRIM:
// the safety window that shows behind keyguard while keyguard is starting
return 12;
case TYPE_KEYGUARD:
// the keyguard; nothing on top of these can take focus, since they are
// responsible for power management when displayed.
return 13;
case TYPE_KEYGUARD_DIALOG:
return 14;
case TYPE_STATUS_BAR_SUB_PANEL:
return 15;
case TYPE_STATUS_BAR:
return 16;
case TYPE_STATUS_BAR_PANEL:
return 17;
case TYPE_VOLUME_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 18;
case TYPE_SYSTEM_OVERLAY:
// the on-screen volume indicator and controller shown when the user
// changes the device volume
return 19;
case TYPE_NAVIGATION_BAR:
// the navigation bar, if available, shows atop most things
return 20;
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
return 21;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
return 22;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
return 23;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
return 24;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
return 25;
case TYPE_SECURE_SYSTEM_OVERLAY:
return 26;
case TYPE_BOOT_PROGRESS:
return 27;
case TYPE_POINTER:
// the (mouse) pointer layer
return 28;
case TYPE_HIDDEN_NAV_CONSUMER:
return 29;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
}
返回值越高则Z轴层级约考上,其中 TYPE_UNIVERSE_BACKGROUND 在最低层,TYPE_HIDDEN_NAV_CONSUMER 在最上层,
从此层级中可以看出常用的两种type的区别,
TYPE_SYSTEM_ALERT 比较低层级,在系统锁屏之下,并且可以显示出系统dialog,并显示响应系统的状态栏和虚拟键盘等。
TYPE_SYSTEM_ERROR 层级较高,会盖住系统锁屏,和其它的系统级控件。
三、权限:
当我尝试设置了一些高层级的type后,发现缺少权限,于是再次调查源码看到:
public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
int type = attrs.type;
outAppOp[0] = AppOpsManager.OP_NONE;
if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
|| type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
return WindowManagerGlobal.ADD_OKAY;
}
String permission = null;
switch (type) {
case TYPE_TOAST:
// XXX right now the app process has complete control over
// this... should introduce a token to let the system
// monitor/control what they are doing.
break;
case TYPE_DREAM:
case TYPE_INPUT_METHOD:
case TYPE_WALLPAPER:
case TYPE_PRIVATE_PRESENTATION:
// The window manager will check these.
break;
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
case TYPE_SYSTEM_ALERT:
case TYPE_SYSTEM_ERROR:
case TYPE_SYSTEM_OVERLAY:
permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
break;
default:
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
if (permission != null) {
if (mContext.checkCallingOrSelfPermission(permission)
!= PackageManager.PERMISSION_GRANTED) {
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
}
}
return WindowManagerGlobal.ADD_OKAY;
}
一些低层级的type需要 SYSTEM_ALERT_WINDOW 权限,一些高层级的需要 INTERNAL_SYSTEM_WINDOW 权限。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
但是尝试一些高层级type时加上
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW "/>
发现没有任何效果,依然提示我没有权限。最后发现 INTERNAL_SYSTEM_WINDOW 是系统权限。系统不允许普通应用程序获得那些type。
不过最后我要说,一般来讲悬浮窗用到的type只要 TYPE_SYSTEM_ALERT 和 TYPE_SYSTEM_ERROR 就够了。