问题的描述:
软件版本为android 10.0, 测试提了一个bug,手机在不分屏时在输入法界面,toast正常显示;但是手机在分屏时,因为显示了输入法界面,toast虽然调用了,但是被输入法界面遮挡看不到。
问题分析:
那这个明显是窗口z-order管理问题,那我们先看看window的dumpsys信息:
1
2adb shell dumpsys window windows
输入法window:
1
2
3
4
5
6
7
8
9
10
11
12Window #0 Window{1ac9429 u0 InputMethod}: mDisplayId=0 stackId=0 mSession=Session{805d144 3396:u0a10092} mClient=android.os.BinderProxy@7030cf3 mOwnerUid=10092 mShowToOwnerOnly=true package=com.iflytek.inputmethod.custom appop=NONE mAttrs={(0,0)(fillxfill) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=INPUT_METHOD fmt=TRANSPARENT wanim=0x1030315 fl=NOT_FOCUSABLE LAYOUT_IN_SCREEN SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS vsysui=LIGHT_NAVIGATION_BAR} Requested w=1920 h=1392 mLayoutSeq=1907 mIsImWindow=true mIsWallpaper=false mIsFloatingLayer=true mWallpaperVisible=false mBaseLayer=151000 mSubLayer=0 mToken=WindowToken{36e543e android.os.Binder@de717c0}
Toast window:
1
2
3
4
5
6
7
8
9
10Window #8 Window{d8b3a0e u0 Toast}: mDisplayId=0 stackId=0 mSession=Session{c221ee 5661:u0a10065} mClient=android.os.BinderProxy@5e7f510 mOwnerUid=10065 mShowToOwnerOnly=true package=com.royole.gallery appop=TOAST_WINDOW mAttrs={(0,144)(wrapxwrap) gr=BOTTOM CENTER sim={adjust=pan} ty=TOAST fmt=TRANSLUCENT wanim=0x1030004 fl=NOT_FOCUSABLE NOT_TOUCHABLE HARDWARE_ACCELERATED} Requested w=290 h=89 mLayoutSeq=1907 mBaseLayer=81000 mSubLayer=0 mToken=WindowToken{4652a4 android.os.Binder@696cd37}
我们可以看到输入法界面是排第0,mBaseLayer为151000,Toast窗口是排第8,mBaseLayer=81000。
那么我们知道窗口z-order是由mBaseLayer的值决定的,其值越大,在UI界面上越显示在前面,那输入法的mBaseLayer值大于Toast的mBaseLayer值,所以Toast必然被输入法窗口遮挡。
那我们追踪一下mBaseLayer的赋值:
WindowState.mBaseLayer其赋值计算:
WindowState.WindowState
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) { // The multiplier here is to reserve space for multiple // windows in the same type layer. mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type); mIsChildWindow = true; ..... } else { // The multiplier here is to reserve space for multiple // windows in the same type layer. mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mSubLayer = 0; mIsChildWindow = false;
其:
1
2
3static final int TYPE_LAYER_MULTIPLIER = 10000; static final int TYPE_LAYER_OFFSET = 1000;
1
2
3
4mBaseLayer = mPolicy.getWindowLayerLw(this) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; mBaseLayer = mPolicy.getWindowLayerLw(this)* 10000 + 1000;
WindowManagerPolicy.getWindowLayerLw方法为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44default int getWindowLayerLw(WindowState win) { return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow()); } default int getWindowLayerFromTypeLw(int type) { if (isSystemAlertWindowType(type)) { throw new IllegalArgumentException("Use getWindowLayerFromTypeLw() or" + " getWindowLayerLw() for alert window types"); } return getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */); } default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) { ...... switch (type) { case TYPE_WALLPAPER: // wallpaper is at the bottom, though the window manager may move it. return 1; case TYPE_PRESENTATION: case TYPE_PRIVATE_PRESENTATION: return APPLICATION_LAYER; ...... case TYPE_SYSTEM_DIALOG: return 7; case TYPE_TOAST://可以看到Toast返回的值是8 // toasts and the plugged-in battery thing return 8; case TYPE_PRIORITY_PHONE: // SIM errors and unlock. Not sure if this really should be in a high layer. return 9; ...... case TYPE_INPUT_METHOD://可以看到输入法返回的值是15 // on-screen keyboards and other such input method user interfaces go here. return 15; case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. return 16;
问题解决:
那么原因我们知道了,那来吧,将Toast返回的值修改为比输入法16大的返回值,验证一下:
1
2
3
4
5case TYPE_TOAST://可以看到Toast返回的值是8 // toasts and the plugged-in battery thing return 18;
验证结果是Toast正常显示,此问题打完收工。
问题拓展:
(1)window类型的定义:
frameworksbasecorejavaandroidviewWindowManager.java
application types window:
1
2
3
4
5
6
7
8
9public static final int FIRST_APPLICATION_WINDOW = 1; public static final int TYPE_BASE_APPLICATION = 1; public static final int TYPE_APPLICATION = 2; public static final int TYPE_APPLICATION_STARTING = 3; public static final int TYPE_DRAWN_APPLICATION = 4; public static final int LAST_APPLICATION_WINDOW = 99;
sub-windows types:
1
2
3
4
5
6
7
8
9
10public 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; 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; public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; public static final int LAST_SUB_WINDOW = 1999;
system-specific window types:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56public 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; 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; 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 TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15; public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16; public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17; public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18; public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19; public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20; public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21; public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22; public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23; public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24; public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26; public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27; public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30; public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31; public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32; public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33; public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34; public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35; public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36; public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37; public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38; public static final int LAST_SYSTEM_WINDOW = 2999;
1
2public static final int INVALID_WINDOW_TYPE = -1;
(2)WindowManagerPolicy.getWindowLayerFromTypeLw的调用堆栈:
PhoneWindowManager.canBeHiddenByKeyguardLw–判断window是否可以被锁屏界面隐藏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47WindowManagerPolicy: at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809) WindowManagerPolicy: at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:790) WindowManagerPolicy: at com.android.server.policy.PhoneWindowManager.canBeHiddenByKeyguardLw(PhoneWindowManager.java:2661) WindowManagerPolicy: at com.android.server.policy.PhoneWindowManager.applyKeyguardPolicyLw(PhoneWindowManager.java:3915) WindowManagerPolicy: at com.android.server.wm.DisplayPolicy.applyPostLayoutPolicyLw(DisplayPolicy.java:2768) WindowManagerPolicy: at com.android.server.wm.DisplayContent.lambda$new$7$DisplayContent(DisplayContent.java:801) WindowManagerPolicy: at com.android.server.wm.-$$Lambda$DisplayContent$JibsaX4YnJd0ta_wiDDdSp-PjQk.accept(Unknown Source:4) WindowManagerPolicy: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1189) WindowManagerPolicy: at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1179) WindowManagerPolicy: at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4380) WindowManagerPolicy: at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4279) WindowManagerPolicy: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:888) WindowManagerPolicy: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:888) WindowManagerPolicy: at com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:2357) WindowManagerPolicy: at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:905) WindowManagerPolicy: at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3953) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:833) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:610) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:567) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95) WindowManagerPolicy: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5108)
WindowToken.canLayerAboveSystemBars–判断window是否可以显示在systembar上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43WindowManagerPolicy: at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809) WindowManagerPolicy: at com.android.server.wm.WindowToken.canLayerAboveSystemBars(WindowToken.java:338) WindowManagerPolicy: at com.android.server.wm.WindowState.skipDecorCrop(WindowState.java:4664) WindowManagerPolicy: at com.android.server.wm.WindowState.calculatePolicyCrop(WindowState.java:4684) WindowManagerPolicy: at com.android.server.wm.WindowStateAnimator.calculateCrop(WindowStateAnimator.java:797) WindowManagerPolicy: at com.android.server.wm.WindowStateAnimator.setSurfaceBoundariesLocked(WindowStateAnimator.java:870) WindowManagerPolicy: at com.android.server.wm.WindowStateAnimator.prepareSurfaceLocked(WindowStateAnimator.java:1095) WindowManagerPolicy: at com.android.server.wm.WindowState.prepareSurfaces(WindowState.java:5095) WindowManagerPolicy: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218) WindowManagerPolicy: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218) WindowManagerPolicy: at com.android.server.wm.DisplayContent$NonAppWindowContainers.prepareSurfaces(DisplayContent.java:5022) WindowManagerPolicy: at com.android.server.wm.WindowContainer.prepareSurfaces(WindowContainer.java:1218) WindowManagerPolicy: at com.android.server.wm.DisplayContent.prepareSurfaces(DisplayContent.java:5180) WindowManagerPolicy: at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3973) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:833) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:610) WindowManagerPolicy: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:567) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105) WindowManagerPolicy: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95) WindowManagerPolicy: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5108)
DisplayContent.addWindowToken–添加windowtoken时调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33WindowManagerPolicy: at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809) WindowManagerPolicy: at com.android.server.wm.DisplayContent$NonAppWindowContainers.lambda$new$0$DisplayContent$NonAppWindowContainers(DisplayContent.java:4927) WindowManagerPolicy: at com.android.server.wm.-$$Lambda$DisplayContent$NonAppWindowContainers$nqCymC3xR9b3qaeohnnJJpSiajc.compare(Unknown Source:6) WindowManagerPolicy: at com.android.server.wm.WindowContainer.addChild(WindowContainer.java:230) WindowManagerPolicy: at com.android.server.wm.DisplayContent$NonAppWindowContainers.addChild(DisplayContent.java:4952) WindowManagerPolicy: at com.android.server.wm.DisplayContent.addWindowToken(DisplayContent.java:1078) WindowManagerPolicy: at com.android.server.wm.DisplayContent.reParentWindowToken(DisplayContent.java:1112) WindowManagerPolicy: at com.android.server.wm.WindowToken.onDisplayChanged(WindowToken.java:263) WindowManagerPolicy: at com.android.server.wm.WindowToken.<init>(WindowToken.java:124) WindowManagerPolicy: at com.android.server.wm.WindowToken.<init>(WindowToken.java:110) WindowManagerPolicy: at com.android.server.wm.WindowManagerService.addWindowToken(WindowManagerService.java:2608) WindowManagerPolicy: at com.android.server.wm.WindowManagerService$LocalService.addWindowToken(WindowManagerService.java:7524) WindowManagerPolicy: at com.android.server.notification.NotificationManagerService$10.enqueueToast(NotificationManagerService.java:2375) WindowManagerPolicy: at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:1114) WindowManagerPolicy: at android.os.Binder.execTransactInternal(Binder.java:1021) WindowManagerPolicy: at android.os.Binder.execTransact(Binder.java:994)
WindowContainer.assignChildLayers–处理子layer时调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39WindowManagerPolicy: at com.android.server.policy.WindowManagerPolicy.getWindowLayerFromTypeLw(WindowManagerPolicy.java:809) WindowManagerPolicy: at com.android.server.wm.DisplayContent$AboveAppWindowContainers.assignChildLayers(DisplayContent.java:4899) WindowManagerPolicy: at com.android.server.wm.DisplayContent$AboveAppWindowContainers.assignChildLayers(DisplayContent.java:4878) WindowManagerPolicy: at com.android.server.wm.WindowContainer.assignChildLayers(WindowContainer.java:1129) WindowManagerPolicy: at com.android.server.wm.WindowContainer.onParentChanged(WindowContainer.java:199) WindowManagerPolicy: at com.android.server.wm.WindowContainer.setParent(WindowContainer.java:170) WindowManagerPolicy: at com.android.server.wm.WindowContainer.addChild(WindowContainer.java:247) WindowManagerPolicy: at com.android.server.wm.DisplayContent$NonAppWindowContainers.addChild(DisplayContent.java:4952) WindowManagerPolicy: at com.android.server.wm.DisplayContent.addWindowToken(DisplayContent.java:1078) WindowManagerPolicy: at com.android.server.wm.DisplayContent.reParentWindowToken(DisplayContent.java:1112) WindowManagerPolicy: at com.android.server.wm.WindowToken.onDisplayChanged(WindowToken.java:263) WindowManagerPolicy: at com.android.server.wm.WindowToken.<init>(WindowToken.java:124) WindowManagerPolicy: at com.android.server.wm.WindowToken.<init>(WindowToken.java:110) WindowManagerPolicy: at com.android.server.wm.WindowManagerService.addWindowToken(WindowManagerService.java:2608) WindowManagerPolicy: at com.android.server.wm.WindowManagerService$LocalService.addWindowToken(WindowManagerService.java:7524) WindowManagerPolicy: at com.android.server.notification.NotificationManagerService$10.enqueueToast(NotificationManagerService.java:2375) WindowManagerPolicy: at android.app.INotificationManager$Stub.onTransact(INotificationManager.java:1114) WindowManagerPolicy: at android.os.Binder.execTransactInternal(Binder.java:1021) WindowManagerPolicy: at android.os.Binder.execTransact(Binder.java:994)
(3)WindowState.mSubLayer–子窗口
计算方法为:
WindowState.WindowState
1
2mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
WindowManagerPolicy.getSubWindowLayerFromTypeLw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28/** * Return how to Z-order sub-windows in relation to the window they are attached to. * Return positive to have them ordered in front, negative for behind. * * @param type The sub-window type code. * * @return int Layer in relation to the attached window, where positive is * above and negative is below. */ default int getSubWindowLayerFromTypeLw(int type) { switch (type) { case TYPE_APPLICATION_PANEL: case TYPE_APPLICATION_ATTACHED_DIALOG: return APPLICATION_PANEL_SUBLAYER;//1 case TYPE_APPLICATION_MEDIA: return APPLICATION_MEDIA_SUBLAYER;//-2 case TYPE_APPLICATION_MEDIA_OVERLAY: return APPLICATION_MEDIA_OVERLAY_SUBLAYER;//-1 case TYPE_APPLICATION_SUB_PANEL: return APPLICATION_SUB_PANEL_SUBLAYER;//2 case TYPE_APPLICATION_ABOVE_SUB_PANEL: return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;//3 } Slog.e("WindowManager", "Unknown sub-window type: " + type); return 0; }
从注解可以看出返回正数就显示在前面,返回负数就显示在后面。
WindowManagerPolicyConstants.java
1
2
3
4
5
6
7int APPLICATION_LAYER = 2; int APPLICATION_MEDIA_SUBLAYER = -2; int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; int APPLICATION_PANEL_SUBLAYER = 1; int APPLICATION_SUB_PANEL_SUBLAYER = 2; int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
最后
以上就是仁爱导师最近收集整理的关于android开发浅谈之窗口管理Z-Order问题的描述:问题分析:问题解决:问题拓展:的全部内容,更多相关android开发浅谈之窗口管理Z-Order问题内容请搜索靠谱客的其他文章。
发表评论 取消回复