当前位置:   article > 正文

WindowState注意事项

cur insets

本文将分析具体WindowState个别关键的成员变量和成员函数。

  1. Window #3 Window{20dd178e u0 com.android.mms/com.android.mms.ui.ConversationList}:
  2. mDisplayId=0 mSession=Session{cb5d53 25296:u0a10013} mClient=android.os.BinderProxy@31ef4b89
  3. mOwnerUid=10013 mShowToOwnerOnly=true package=com.android.mms appop=NONE
  4. mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#132 ty=1 fl=#5810100 pfl=0x8 wanim=0xa100000 vsysui=0x500 surfaceInsets=Rect(0, 0 - 0, 0) meizuFlags=0xca06 imeOffset=-1 splitActionBarHeight=144Meizu WM.LayoutParams [ flags=0x0] }
  5. Requested w=1080 h=1920 mLayoutSeq=517
  6. mBaseLayer=21000 mSubLayer=0 mAnimLayer=21015+0=21015 mLastLayer=21015
  7. mToken=AppWindowToken{25ebcb64 token=Token{2ca234f6 ActivityRecord{a4babb8 u0 com.android.mms/.ui.ConversationList t61}}}
  8. mRootToken=AppWindowToken{25ebcb64 token=Token{2ca234f6 ActivityRecord{a4babb8 u0 com.android.mms/.ui.ConversationList t61}}}
  9. mAppToken=AppWindowToken{25ebcb64 token=Token{2ca234f6 ActivityRecord{a4babb8 u0 com.android.mms/.ui.ConversationList t61}}}
  10. mViewVisibility=0x0 mHaveFrame=true mObscured=false
  11. mSeq=0 mSystemUiVisibility=0x500
  12. mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
  13. mConfiguration={1.0 ?mcc?mnc zh_CN ldltr sw360dp w360dp h615dp 480dpi nrml long port finger -keyb/v/h -nav/h themeChanged.0 s.9}
  14. mHasSurface=true mShownFrame=[0.0,0.0][1080.0,1920.0] isReadyForDisplay()=true
  15. mFrame=[0,0][1080,1920] last=[0,0][1080,1920]
  16. mSystemDecorRect=[0,0][1080,1920] last=[0,0][0,0]
  17. Frames: containing=[0,0][1080,1920] parent=[0,0][1080,1920]
  18. display=[0,0][1080,1920] overscan=[0,0][1080,1920]
  19. content=[0,75][1080,1920] visible=[0,75][1080,1920]
  20. decor=[0,0][1080,1920]
  21. Cur insets: overscan=[0,0][0,0] content=[0,75][0,0] visible=[0,75][0,0] stable=[0,75][0,144]
  22. Lst insets: overscan=[0,0][0,0] content=[0,75][0,0] visible=[0,75][0,0] stable=[0,75][0,144]
  23. WindowStateAnimator{2aeee9fd com.android.mms/com.android.mms.ui.ConversationList}:
  24. mSurface=Surface(name=com.android.mms/com.android.mms.ui.ConversationList)
  25. mDrawState=HAS_DRAWN mLastHidden=false
  26. Surface: shown=true layer=21015 alpha=1.0 rect=(0.0,0.0) 1080.0 x 1920.0

1、Session类对象mSession

每个WindowState都有一个Session类成员变量,那么每个窗体保存的都是同一个mSession吗?还是每个窗体的mSession都不同呢?dump一下便知道了。dump日志告诉我上述两种情况都不是,其实是每个UI进程的全部窗体保存的是同一个Session。而每个UI进程之间的Session又是不同的。

Session顾名思义就是会话的意思,是ViewRootImpl用来调用WMS服务功能的东东,这个能够从Session类中的函数能够看出来。每个UI进程在何时创建一个Session的呢?是在add第一个View时创建的,这点大家能够去研究下源代码。Session类继承IWindowSession.Stub。能够知道WindowState中保存的是本地对象,而ViewRootImpl中 mWindowSession保存的是代理对象。

2、IWindow类对象mClient

mClient是一个代理对象,本地对象保存在ViewRootImpl中的mWindow中。

WMS利用mClient来通知ViewRootImpl一些状态的改变等。mClient代表的是UI进程側的一个窗体。

3、mOwnerUid

该变量保存的是UID。UID在Linux中是为多用户设计的,而在Android中赋予了新的使命--数据共享,android为每一个应用差点儿都分配了不同的UID,假设要实现两个程序的互訪,能够定义同样的android:sharedUserId,而且签名同样便可互訪。

4、mShowToOwnerOnly

这个变量是为多用户准备的,详细作用是标示一个窗体是否只在当前UID下才干显示。能够查看DisplayContent.switchUserStacks()关于多用户转换逻辑。

  1. boolean isHiddenFromUserLocked() {
  2. return win.mShowToOwnerOnly
  3. && UserHandle.getUserId(win.mOwnerUid) != mService.mCurrentUserId;
  4. }
5、mAppOp

该变量保存着该窗体特有的一些权限,比方假设该窗体是一个SYSTEM_ALERT_WINDOW窗体,那么mAppOp中会保存这个特殊权限。在非常多地方权限管理AppOpsManager会检查这个窗体能否申请到相应的资源。

6、mAttrs

这个变量中保存了差点儿全部的关于该窗体的属性信息。比方窗体类型、flags、高度、宽度等等。

computeFrameLw()中就是依据mAttrs来确定窗体Frame的。

7、mRequestedWidth、mRequestedHeight

* The window size that was requested by the application.  These are in the application's coordinate space*,保存着应用要求的窗体高和宽,能够查看WMS.relayoutWindow()函数。

8、mLayoutSeq

WMS.performLayoutLockedInner被调用一次。WMS.mLayoutSeq就加1,在一次Layout过程中,假设对某一个窗体调用了mPolicy.layoutWindowLw()函数进行布局,win.mLayoutSeq 就更新为WMS.mLayoutSeq值。

所以通过查看WindowState.mLayoutSeq值就能够知道该窗体是在哪一次又一次布局过的。

9、mAttachedWindow

假设该变量不为null,表示当前窗体须要附加在mAttachedWindow之上。当前窗体是mAttachedWindow的子窗体。mAttachedWindow的赋值流程例如以下:当UI进程须要加入一个Window时。终于会调用WMS.addWindow()。addWindow()函数中有这段代码:

  1. if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
  2. attachedWindow = windowForClientLocked(null, attrs.token, false);
  3. if (attachedWindow == null) {
  4. Slog.w(TAG, "Attempted to add window with token that is not a window: "
  5. + attrs.token + ". Aborting.");
  6. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  7. }
  8. if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
  9. && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
  10. Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
  11. + attrs.token + ". Aborting.");
  12. return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
  13. }
  14. }
假设加入的Window是一个子窗体,即(type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW),那么会依据attrs.token调用windowForClientLocked()找到父窗体,能够推測并得出父窗体跟子窗体的attrs中保存的是同一个W对象的结论,结论是否正确待验证。windowForClientLocked()找到的父窗体WindowState会保存在mAttachedWindow中。

10、mLayoutAttached

对于(type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)的窗体,该属性在mAttrs.type !=WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG才为true,也就是说一般的子窗体这个属性为true。除非type==TYPE_APPLICATION_ATTACHED_DIALOG才为false;而对于非子窗体,该属性必须为false。mLayoutAttached的值会影响mPolicy.layoutWindowLw(),详细影响请研究performLayoutLockedInner()函数。

11、mIsImWindow、mIsWallpaper、mIsFloatingLayer

前两个变量非常好理解,就是指示该窗体是否是输入法窗体、壁纸窗体,mIsFloatingLayer是什么?该变量在WindowState构造函数中赋值:

mIsFloatingLayer = mIsImWindow || mIsWallpaper;
假设当前窗体是输入法窗体或壁纸窗体,就为true,否则为false;所有搜索了一下这个变量的使用。没有地方使用这个变量,也就是说这个变量是打酱油的。

12、mWallpaperVisible

该变量是壁纸窗体WindowState的可见属性,其它窗体没实用到该属性。

壁纸窗体本身不复杂,复杂的是壁纸窗体必须附在某些窗体之下。而且參与一些窗体动画之类的逻辑,导致WMS中到处都有wallpaper逻辑,看起来相当蛋疼。

13、mBaseLayer

  1. mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
  2. * WindowManagerService.TYPE_LAYER_MULTIPLIER
  3. + WindowManagerService.TYPE_LAYER_OFFSET;
android中全部的WindowState都是根据窗体Z轴值来排列的。高度越高,越可见。这个Z轴高度的计算是基于mBaseLayer、可见性等等因素。上述代码是不论什么窗体mBaseLayer的计算公式,能够看出mBaseLayer=窗体类型值*10000+1000,普通窗体类型值为2,所以普通窗体mBaseLayer=21000,这点能够通过dump日志验证。

14、mSubLayer

对于非子窗体,该变量值为0。对于子窗体mSubLayer的值为

mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
mPolicy指向PhoneWindowManager,获得的mSubLayer可正可负,表示该子窗体在父窗体的上面或以下。

15、mLayer

mLayer保存的是该窗体的Layer高度值,但不是终于Z轴值,终于Z轴值是在mLayer的基础上再添加一个调整值。mLayer、终于Z轴值的计算是在WMS.assignLayersLocked()中完毕的。而且Z轴值保存在WindowStateAnimator.mAnimLayer中。

看看assignLayersLocked()函数:

  1. private final void assignLayersLocked(WindowList windows) {
  2. int N = windows.size();
  3. int curBaseLayer = 0;
  4. int curLayer = 0;
  5. int i;
  6. boolean anyLayerChanged = false;
  7. for (i=0; i<N; i++) {
  8. final WindowState w = windows.get(i);
  9. final WindowStateAnimator winAnimator = w.mWinAnimator;
  10. boolean layerChanged = false;
  11. int oldLayer = w.mLayer;
  12. if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
  13. || (i > 0 && w.mIsWallpaper)) {
  14. curLayer += WINDOW_LAYER_MULTIPLIER;
  15. w.mLayer = curLayer;
  16. } else {
  17. curBaseLayer = curLayer = w.mBaseLayer;
  18. w.mLayer = curLayer;
  19. }
  20. if (w.mLayer != oldLayer) {
  21. layerChanged = true;
  22. anyLayerChanged = true;
  23. }
  24. final AppWindowToken wtoken = w.mAppToken;
  25. oldLayer = winAnimator.mAnimLayer;
  26. if (w.mTargetAppToken != null) {
  27. winAnimator.mAnimLayer =
  28. w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
  29. } else if (wtoken != null) {
  30. winAnimator.mAnimLayer =
  31. w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
  32. } else {
  33. winAnimator.mAnimLayer = w.mLayer;
  34. }
  35. if (w.mIsImWindow) {
  36. winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
  37. } else if (w.mIsWallpaper) {
  38. winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
  39. }
  40. if (winAnimator.mAnimLayer != oldLayer) {
  41. layerChanged = true;
  42. anyLayerChanged = true;
  43. }
  44. if (layerChanged && w.getStack().isDimming(winAnimator)) {
  45. scheduleAnimationLocked();
  46. }
  47. }
  48. //TODO (multidisplay): Magnification is supported only for the default display.
  49. if (mDisplayMagnifier != null && anyLayerChanged
  50. && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
  51. mDisplayMagnifier.onWindowLayersChangedLocked();
  52. }
  53. }
传进来的參数windows是全部窗体列表。大致排好序的。对于同一类型窗体的第一个窗体w.mLayer=w.mBaseLayer。第二个、第三个依次添加WINDOW_LAYER_MULTIPLIER(5),这个能够通过dump日志进行验证。

16、WindowToken类对象mToken

WindowToken是窗体令牌,跟WindowState之间的关系參考老罗的博客,引用一下“

Window管理服务WindowManagerService中,不管是AppWindowToken对象。还是WindowToken对象。它们都是用来描写叙述一组有着同样令牌的窗体的。每个窗体都是通过一个WindowState对象来描写叙述的。比如。一个Activity组件窗体可能有一个启动窗体(Starting Window)。还有若干个子窗体,那么这些窗体就会组成一组,而且都是以Activity组件在Window管理服务WindowManagerService中所相应的AppWindowToken对象为令牌的。从抽象的角度来看,就是在Window管理服务WindowManagerService中。每个令牌(AppWindowToken或者WindowToken)都是用来描写叙述一组窗体(WindowState)的,而且每个窗体的子窗体也是与它同属于一个组,即都有着同样的令牌。

还是自己分析一下,mToken的赋值在构造WindowState时传进来的。详细还的分析WMS.addWindow()函数,关键代码例如以下:

  1. WindowToken token = mTokenMap.get(attrs.token);
  2. if (token == null) {
  3. if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
  4. Slog.w(TAG, "Attempted to add application window with unknown token "
  5. + attrs.token + ". Aborting.");
  6. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  7. }
  8. if (type == TYPE_INPUT_METHOD) {
  9. Slog.w(TAG, "Attempted to add input method window with unknown token "
  10. + attrs.token + ". Aborting.");
  11. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  12. }
  13. if (type == TYPE_WALLPAPER) {
  14. Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
  15. + attrs.token + ". Aborting.");
  16. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  17. }
  18. if (type == TYPE_DREAM) {
  19. Slog.w(TAG, "Attempted to add Dream window with unknown token "
  20. + attrs.token + ". Aborting.");
  21. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  22. }
  23. token = new WindowToken(this, attrs.token, -1, false);
  24. addToken = true;
  25. } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
  26. AppWindowToken atoken = token.appWindowToken;
  27. if (atoken == null) {
  28. Slog.w(TAG, "Attempted to add window with non-application token "
  29. + token + ". Aborting.");
  30. return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
  31. } else if (atoken.removed) {
  32. Slog.w(TAG, "Attempted to add window with exiting application token "
  33. + token + ". Aborting.");
  34. return WindowManagerGlobal.ADD_APP_EXITING;
  35. }
  36. if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
  37. // No need for this guy!
  38. if (localLOGV) Slog.v(
  39. TAG, "**** NO NEED TO START: " + attrs.getTitle());
  40. return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
  41. }
  42. } else if (type == TYPE_INPUT_METHOD) {
  43. if (token.windowType != TYPE_INPUT_METHOD) {
  44. Slog.w(TAG, "Attempted to add input method window with bad token "
  45. + attrs.token + ". Aborting.");
  46. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  47. }
  48. } else if (type == TYPE_WALLPAPER) {
  49. if (token.windowType != TYPE_WALLPAPER) {
  50. Slog.w(TAG, "Attempted to add wallpaper window with bad token "
  51. + attrs.token + ". Aborting.");
  52. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  53. }
  54. } else if (type == TYPE_DREAM) {
  55. if (token.windowType != TYPE_DREAM) {
  56. Slog.w(TAG, "Attempted to add Dream window with bad token "
  57. + attrs.token + ". Aborting.");
  58. return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
  59. }
  60. }
  61. win = new WindowState(this, session, client, token,
  62. attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
mTokenMap是一个HashMap,里面成对的保存着attrs.token和WindowToken

  1. if (addToken) {
  2. mTokenMap.put(attrs.token, token);
  3. }

attrs.token比較关键,new一个新的WindowToken必须是attrs.token第一次被加入到WMS中时,假设之间已经加入过一个与attrs.token相应的窗体,那么就使用之前的WindowToken,就是说attrs.token同样的窗体,相应的WindowToken是同样的,那么attrs.token是什么东西呢?特别说明下,相应壁纸和输入法窗体比較特殊,这两个窗体是通过WMS.addWindowToken()来加入WindowToken到WMS中的,而不是像普通窗体那样通过addWindow(),这个大家搜一下源代码就知道了。再来研究下attrs.token。还是算了吧。全然不知道从哪里赋值的,只是老罗已经给出关系图了,这个attrs.token应该就是跟ActivityRecord相应的东西。

可是比較有趣的是对于StatusBar、Keyguard、KeyguardScrim及自己调用mWindowManager.addView()加入的View的WindowToken都是同一个WindowToken,这点通过dump日志能够验证。

17、mRootToken

mRootToken就是当前窗体的根窗体令牌。这个非常好理解,比方某一个窗体的mAttachedWindow不为null,那么mRootToken就指向mAttachedWindow根部窗体的WindowToken。这个值能够为WindowToken,也能够为AppWindowToken,不可能为null。

  1. WindowState appWin = this;
  2. while (appWin.mAttachedWindow != null) {
  3. appWin = appWin.mAttachedWindow;
  4. }
  5. WindowToken appToken = appWin.mToken;
  6. while (appToken.appWindowToken == null) {
  7. WindowToken parent = mService.mTokenMap.get(appToken.token);
  8. if (parent == null || appToken == parent) {
  9. break;
  10. }
  11. appToken = parent;
  12. }
  13. mRootToken = appToken;
  14. mAppToken = appToken.appWindowToken;

18、mAppToken

mAppToken指向mAttachedWindow根部窗体的appWindowToken,假设mAttachedWindow根部窗体的appWindowToken不是一个Activity窗体。那么就为null,否则就为null。对于Activity的窗体难道不走WMS.addWindow()?由于addWindow()中没有new AppWindowToken逻辑,Activity窗体令牌是用AppWindowToken来描写叙述的。好诡异。

19、AppWindowToken

该类用来描写叙述一个Activity窗体令牌。对于输入法。壁纸,自己addView的窗体,及PopupWindow等都是用WindowToken来描写叙述窗体令牌的。

上面第18条说了既然Activity窗体令牌是用AppWindowToken来描写叙述的,但addWindow()的逻辑中并没有针对Activity窗体new AppWindowToken。还是研究下其它地方看看是怎么回事。源代码里仅仅有addAppToken()函数中有new AppWindowToken的操作。想必对于Activity来说。会调用这个函数来创建一个AppWindowToken对象。在第16条中提到WindowToken与attrs.token一一相应,而且attrs.token会保存在WindowToken.token中,而对于AppWindowToken来说。与IApplicationToken一一相应,而且保存在AppWindowToken.token中,IApplicationToken是啥稍后再说。

  1. public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
  2. int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
  3. int configChanges) {
  4. long inputDispatchingTimeoutNanos;
  5. synchronized(mWindowMap) {
  6. AppWindowToken atoken = findAppWindowToken(token.asBinder());
  7. if (atoken != null) {
  8. Slog.w(TAG, "Attempted to add existing app token: " + token);
  9. return;
  10. }
  11. atoken = new AppWindowToken(this, token);
  12. atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
  13. atoken.groupId = taskId;
  14. atoken.appFullscreen = fullscreen;
  15. atoken.showWhenLocked = showWhenLocked;
  16. atoken.requestedOrientation = requestedOrientation;
  17. atoken.layoutConfigChanges = (configChanges &
  18. (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
  19. Task task = mTaskIdToTask.get(taskId);
  20. if (task == null) {
  21. task = createTask(taskId, stackId, userId, atoken);
  22. } else {
  23. task.addAppToken(addPos, atoken);
  24. }
  25. mTokenMap.put(token.asBinder(), atoken);
  26. atoken.hidden = true;
  27. atoken.hiddenRequested = true;
  28. }
  29. }
这段代码逻辑非常easy懂,就是假设IApplicationToken已经加入到WMS中了就直接返回,否则new AppWindowToken。并把IApplicationToken作为參数保存在

AppWindowToken.appToken中,然后设置一下AppWindowToken的一些属性,包含groupId、appFullscreen、showWhenLocked、requestedOrientation、layoutConfigChanges等。

mTaskIdToTask维护了TaskId和Task对,假设调用addAppToken时指定一个新的TaskId。那么就须要调用createTask()创建一个新的Task。否则就找到相应的Task。并把AppWindowToken加入到Task相应的位置,位置由addAppToken()的參数指定。还有新new出来的AppWindowToken属性hidden和hiddenRequested都为true。表示为隐藏。

特别说一下AppWindowToken的构造函数:

  1. AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
  2. super(_service, _token.asBinder(),
  3. WindowManager.LayoutParams.TYPE_APPLICATION, true);
  4. appWindowToken = this;
  5. appToken = _token;
  6. mInputApplicationHandle = new InputApplicationHandle(this);
  7. mAnimator = service.mAnimator;
  8. mAppAnimator = new AppWindowAnimator(this);
  9. }

AppWindowToken是继承WindowToken的。对于AppWindowToken来说appWindowToken变量不为null,指向本身,对于WindowToken来说appWindowToken变量为null。因此能够依据WindowToken.appWindowToken来推断该窗体是否是Activity窗体令牌。从构造函数中还能够看出每一个AppWindowToken.mAnimator均指向WMS.mAnimator对象,每一个AppWindowToken.mAppAnimator都不同。

addAppToken()函数在ActivityStack.startActivityLocked()中被调用,而startActivityLocked()被调用的流程例如以下:ActivityStackSupervisor.startActivityLocked()-->ActivityStackSupervisor.startActivityUncheckedLocked()-->ActivityStack.startActivityLocked()。这个以后再研究。

20、mTargetAppToken

对与输入法窗体,mTargetAppToken就是指向待输入的窗体,对于壁纸窗体,mTargetAppToken为null。搜了下源代码,貌似仅仅有输入法窗体mTargetAppToken才不为空,其它全部窗体该变量为null。这个变量应该是专门用来处理输入法窗体相关的逻辑。

21、mViewVisibility

这个是保存的是当前窗体的可见性状态。这个变量仅仅有在两个地方可能会改变其值。一个是构造WindowState时,会初始化该值,还有一个在WMS.relayoutWindow()函数中。部分代码例如以下:

  1. boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility
  2. || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
  3. || (!win.mRelayoutCalled));
  4. boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
  5. && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
  6. wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
  7. win.mRelayoutCalled = true;
  8. final int oldVisibility = win.mViewVisibility;
  9. win.<span style="color:#ff0000;">mViewVisibility </span>= viewVisibility;
viewVisibility是relayoutWindow()函数中的參数。能够知道一个WindowState的可见性是通过WMS.relayoutWindow()来更新的。

22、mHaveFrame

mHaveFrame标示该窗体是否有Frame,事实上准确的说应该是该窗体是否已经准备好了各种Frame尺寸,换句话就是说是否调用过WindowState.computeFrameLw()函数,仅仅要调用过,mHaveFrame就为true。

23、mObscured

标识该窗体是否做模糊化处理?详细是什么,没搞清。

正常情况下全部窗体mObscured为false。

24、mSeq

貌似跟“ StatusBar on multiple screens”有关,没研究清楚。

正常情况下全部窗体mSeq为0.

25、mSystemUiVisibility

这个变量标识当前窗体下STATUSBAR、导航栏的可见属性值,这个值能够通过setSystemUiVisibility()函数来更新,mSystemUiVisibility通常是跟窗体的attrs.systemUiVisibility属性值保持一致的。普通情况下mSystemUiVisibility值为0,

  1. systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
  2. .....
  3. if (attrs != null && seq == win.mSeq) {
  4. win.mSystemUiVisibility = systemUiVisibility;
  5. }
26、mPolicyVisibility

mPolicyVisibility是窗体显示策略变量。与第21条的mViewVisibility不同。mViewVisibility用来保存当前窗体是否可见的状态。而mPolicyVisibility指导下一步该窗体是否可见。进而做一些逻辑处理。

27、mPolicyVisibilityAfterAnim

由名字能够知道窗体动画播完后mPolicyVisibility的值需更新为mPolicyVisibilityAfterAnim的值

  1. boolean stepAnimationLocked(long currentTime) {
  2. .......
  3. if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) {
  4. if (DEBUG_VISIBILITY) {
  5. Slog.v(TAG, "Policy visibility changing after anim in " + this + ": "
  6. + mWin.mPolicyVisibilityAfterAnim);
  7. }
  8. mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
  9. mWin.mDisplayContent.layoutNeeded = true;
  10. if (!mWin.mPolicyVisibility) {
  11. if (mService.mCurrentFocus == mWin) {
  12. if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
  13. "setAnimationLocked: setting mFocusMayChange true");
  14. mService.mFocusMayChange = true;
  15. }
  16. mService.enableScreenIfNeededLocked();
  17. }
  18. }
28、mAppOpVisibility

mAppOpVisibility也是一个显示控制变量。默觉得true,在setAppOpVisibilityLw()函数中设置其值。

  1. public void setAppOpVisibilityLw(boolean state) {
  2. if (mAppOpVisibility != state) {
  3. mAppOpVisibility = state;
  4. if (state) {
  5. // If the policy visibility had last been to hide, then this
  6. // will incorrectly show at this point since we lost that
  7. // information. Not a big deal -- for the windows that have app
  8. // ops modifies they should only be hidden by policy due to the
  9. // lock screen, and the user won't be changing this if locked.
  10. // Plus it will quickly be fixed the next time we do a layout.
  11. showLw(true, true);
  12. } else {
  13. hideLw(true, true);
  14. }
  15. }
  16. }
setAppOpVisibilityLw()函数在addWindow()和updateAppOpsState()中被调用。跟AppOpsManager权限检查紧密结合在一起。mAppOpVisibility就是跟权限管理器相关的显示属性。

29、mAttachedHidden

mAttachedHidden属性标识父窗体的可见状态。对于子窗体才设置mAttachedHidden属性。

30、mRelayoutCalled

mRelayoutCalled标识该窗体是否调用过relayoutWindow()函数,仅仅有调用过mRelayoutCalled一次便一直为true。

31、mLayoutNeeded

mLayoutNeeded用来在UI进程在调用WMS.relayoutWindow()时记录窗体是否须要Layout,假设窗体大小发生改变、WindowManager.LayoutParams发生改变,那么mLayoutNeeded就设为true。等到调用performLayoutAndPlaceSurfacesLocked()-->performLayoutAndPlaceSurfacesLockedLoop()-->performLayoutAndPlaceSurfacesLockedInner()-->performLayoutLockedInner()时。mLayoutNeeded为true时才调用mPolicy.layoutWindowLw()。


32、mXOffset、mYOffset

这个值表示窗体的相对于屏幕左上角坐标原点的偏移量。

对于一般窗体及自己addView的窗体,这两个值为0。壁纸窗体mXOffset一般为负。只是我在源代码里也仅仅有看到壁纸窗体的mXOffset才可能不为0,其它窗体不会动这个值。

  1. boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh,
  2. boolean sync) {
  3. boolean changed = false;
  4. boolean rawChanged = false;
  5. float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
  6. float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
  7. int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
  8. int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
  9. changed = wallpaperWin.mXOffset != offset;
  10. if (changed) {
  11. if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper "
  12. + wallpaperWin + " x: " + offset);
  13. wallpaperWin.mXOffset = offset;
  14. }
33、getTouchableRegion()

  1. public void getTouchableRegion(Region outRegion) {
  2. final Rect frame = mFrame;
  3. switch (mTouchableInsets) {
  4. default:
  5. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
  6. outRegion.set(frame);
  7. break;
  8. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
  9. applyInsets(outRegion, frame, mGivenContentInsets);
  10. break;
  11. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
  12. applyInsets(outRegion, frame, mGivenVisibleInsets);
  13. break;
  14. case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
  15. final Region givenTouchableRegion = mGivenTouchableRegion;
  16. outRegion.set(givenTouchableRegion);
  17. outRegion.translate(frame.left, frame.top);
  18. break;
  19. }
  20. }
  21. }

获取一个窗体的触摸区域。触摸区域的计算跟mTouchableInsets有关。mTouchableInsets指示当前窗体的触摸区域怎样计算。“Flag indicating whether the touchable region should be adjusted by the visible insets”。


其实真正的触摸区域计算并非全然调用getTouchableRegion()来获取,这点能够通过InputMonitor.addInputWindowHandleLw()看出来

  1. final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
  2. | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
  3. if (modal && child.mAppToken != null) {
  4. // Limit the outer touch to the activity stack region.
  5. flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
  6. inputWindowHandle.touchableRegion.set(child.getStackBounds());
  7. } else {
  8. // Not modal or full screen modal
  9. child.getTouchableRegion(inputWindowHandle.touchableRegion);
  10. }
updateInputWindowsLw()-->addInputWindowHandleLw()会将WMS中WindowList中的全部窗体更新到InputDispatcher中去,方便InputDispatcher依据窗体关系和触摸区域找到对应的窗体,然后将触摸事件分发给找到的窗体,而每一个窗体的触摸区域便是上面这段代码设定的。

能够看出对于无WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL和WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE属性的Activity窗体,触摸区域等于WindowState.getStackBounds(),其它类型窗体的触摸区域则通过getTouchableRegion()计算得来。

34、mConfiguration

这个变量保存值跟WMS.mCurConfiguration是全然同样的,能够通过日志进行验证。

35、mHasSurface

该变量指示是否为该窗体new 一个SurfaceControl对象。即调用WindowState.mWinAnimator.createSurfaceLocked()来创建。SurfaceControl是WMS与SurfaceFlinger通信的接口之中的一个。每个WindowState都相应有一个SurfaceControl,还相应在SurfaceFlinger中一个Layer对象。

36、mShownFrame

非全屏应用:mShownFrame=[0.0,0.0][720.0,1280.0]

全屏应用:    mShownFrame=[0.0,0.0][720.0,1280.0]

壁纸:            mShownFrame=[-310.0,0.0][1030.0,1280.0]

mShownFrame的计算在WindowStateAnimator.computeShownFrameLocked()中完毕。mShownFrame设置到SurfaceFlinger中是在WindowStateAnimator.setSurfaceBoundariesLocked()中完毕,保存在Layer的mCurrentState.transform.set(x, y)和mCurrentState.requested中。

37、isReadyForDisplay()

  1. boolean isReadyForDisplay() {
  2. if (mRootToken.waitingToShow &&
  3. mService.mAppTransition.isTransitionSet()) {
  4. return false;
  5. }
  6. return mHasSurface && mPolicyVisibility && !mDestroying
  7. && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
  8. && !mRootToken.hidden)
  9. || mWinAnimator.mAnimation != null
  10. || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
  11. }

函数虽短,理解起来非常费劲。。

。通过日志来看,仅仅有当前显示的窗体isReadyForDisplay()才返回true。

38、mFrame

非全屏应用:mFrame=[0,0][720,1280]

全屏应用:    mFrame=[0,0][720,1280]

壁纸:           mFrame=[0,0][1340,1280]

mFrame的计算在WindowState.computeFrameLw()中完毕:

  1. Gravity.apply(mAttrs.gravity, w, h, mContainingFrame,
  2. (int) (x + mAttrs.horizontalMargin * pw),
  3. (int) (y + mAttrs.verticalMargin * ph), mFrame);
  4. //System.out.println("Out: " + mFrame);
  5. // Now make sure the window fits in the overall display.
  6. Gravity.applyDisplay(mAttrs.gravity, df, mFrame);
详细怎样计算可自行细致研究。

39、mSystemDecorRect

非全屏应用:mSystemDecorRect=[0,50][720,1280]

全屏应用:    mSystemDecorRect=[0,0][720,1280]

壁纸:            mSystemDecorRect=[0,0][1340,1280]

mSystemDecorRect在updateSurfaceWindowCrop()和applyDecorRect()中赋值。终于通过mSurfaceControl.setWindowCrop(w.mSystemDecorRect)将mSystemDecorRect设置到SurfaceFlinger中去,SurfaceFlinger中会调用layer-->setCrop()保存这个Crop值。至于这个是做什么用的,没搞清。

40、mCompatFrame

兼容模式下的Frame。手机的应用一般不会处于兼容模式下。平板才会?

41、mContainingFrame、mDisplayFrame、mParentFrame、mOverscanFrame、mContentFrame、mVisibleFrame、mDecorFrame

这些Frame之间的关系???虽不明,但觉厉。。。

42、mWinAnimator

WindowStateAnimator类对象。窗体动画类。但不全然跟窗体动画相关。


43、mExiting

表示当前正在运行退出动画。

44、mDestroying

当一个窗体变为不可见。那么这个窗体的Surface须要销毁Wallpaper例外。窗体播完退出动画时在finishExit()中把该WindowState加到WMS.mDestroySurface列表中,同一时候mDestroying设为true。

在下一次调用performLayoutAndPlaceSurfacesLockedInner()时,便把mDestroySurface列表中全部窗体的surface都销毁掉。

45、mRemoveOnExit

 /*Completely remove from window manager after exit animation?

*/

当调用removeWindowLocked()移除一个窗体时。此时假设该窗体mExiting=true或正在播动画,mRemoveOnExit就设为true,表示等待动画退出后全然remove该窗体。等待被移除的窗体保存在WMS.mPendingRemove列表中。

46、mOrientationChanging

* Set when the orientation is changing and this window has not yet been updated for the new orientation.*

当调用updateRotationUncheckedLocked()时,会把每一个WindowState的mOrientationChanging设为true。很多其它关于应用转屏方向的请參考:http://blog.csdn.net/siobhan/article/details/8767369,兴许再研究下。

  1. final WindowList windows = displayContent.getWindowList();
  2. for (int i = windows.size() - 1; i >= 0; i--) {
  3. WindowState w = windows.get(i);
  4. if (w.mHasSurface) {
  5. if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
  6. w.mOrientationChanging = true;
  7. mInnerFields.mOrientationChangeComplete = false;
  8. }
  9. w.mLastFreezeDuration = 0;
  10. }
47、mAppFreezing

App冻结?AMS这边当启动一个应用或其它场景下时就会调用ActivityRecord.startFreezingScreenLocked()-->WMS.startAppFreezingScreen()-->startAppFreezingScreenLocked(),然后将属于与ActivityRecord相应的AppWindowToken的全部窗体及子窗体的mAppFreezing设为true,详细作用看源代码也没研究出来。感觉是防止更改该窗体的一些信息?

48、mTurnOnScreen

假设该窗体设置了WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON属性,mTurnOnScreen就为true。

看下解释:

  1. /** Window flag: when set as a window is being added or made
  2. * visible, once the window has been shown then the system will
  3. * poke the power manager's user activity (as if the user had woken
  4. * up the device) to turn the screen on. */
再看下WMS中performLayoutAndPlaceSurfacesLockedInner()中的部分代码:

  1. if (mTurnOnScreen) {
  2. if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
  3. mPowerManager.wakeUp(SystemClock.uptimeMillis());
  4. mTurnOnScreen = false;
  5. }

代码非常清楚告诉我。假设一个窗体加入了WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON属性,那么在一次UI刷新中会调用 mPowerManager.wakeUp()唤醒系统,也就是保持亮屏吧。

49、mLastFreezeDuration

 * How long we last kept the screen frozen.*

上一次窗体冻结持续时长。

50、mHScale、mVScale

老罗博客解释:当这个WindowManager.LayoutParams对象的成员变量flags的WindowManager.LayoutParams.FLAG_SCALED位不等于0的时候。就说明须要给Activity窗体的大小设置缩放因子。缩放因子分为两个维度,各自是宽度缩放因子和高度缩放因子,保存在WindowState对象win的成员变量HScale和VScale中,计算方法各自是用应用程序进程请求设置Activity窗体中的宽度和高度除以Activity窗体在布局參数中所设置的宽度和高度。

从日志来看,差点儿全部的窗体这两个值都为1。

51、reportFocusChangedSerialized()

这个函数作用从名字就能够看出来。就是“Report a focus change”,还是研究下:

  1. public void reportFocusChangedSerialized(boolean focused, boolean inTouchMode) {
  2. try {
  3. mClient.windowFocusChanged(focused, inTouchMode);
  4. } catch (RemoteException e) {
  5. }
  6. if (mFocusCallbacks != null) {
  7. final int N = mFocusCallbacks.beginBroadcast();
  8. for (int i=0; i<N; i++) {
  9. IWindowFocusObserver obs = mFocusCallbacks.getBroadcastItem(i);
  10. try {
  11. if (focused) {
  12. obs.focusGained(mWindowId.asBinder());
  13. } else {
  14. obs.focusLost(mWindowId.asBinder());
  15. }
  16. } catch (RemoteException e) {
  17. }
  18. }
  19. mFocusCallbacks.finishBroadcast();
  20. }
  21. }
这个函数在WMS.updateFocusedWindowLocked()函数中被调用。updateFocusedWindowLocked会调用computeFocusedWindowLocked()来又一次获取当前的焦点窗体,假设焦点窗体有变更就会调用 reportFocusChangedSerialized()。

回到上面的代码,首先通过跨Binder调用windowFocusChanged(),也就是会调用ViewRootImpl.W.windowFocusChanged()函数,windowFocusChanged()函数中会做一些输入法等处理逻辑,这个以后再研究。

终点。

版权声明:本文博主原创文章,博客,未经同意不得转载。

转载于:https://www.cnblogs.com/lcchuguo/p/4852415.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/574703
推荐阅读
相关标签
  

闽ICP备14008679号