博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DisplayContent、StackBox、TaskStack笔记
阅读量:5277 次
发布时间:2019-06-14

本文共 12422 字,大约阅读时间需要 41 分钟。

文章仅零散记录自己的一点理解,仅供自己參考。

每一个显示设备,都有一个Display对象,DisplayManagerService专门管理这些Display。

1、DisplayContent()

    DisplayContent(Display display, WindowManagerService service) {        mDisplay = display;        mDisplayId = display.getDisplayId();        display.getDisplayInfo(mDisplayInfo);        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;        mService = service;        StackBox newBox = new StackBox(service, this, null);        mStackBoxes.add(newBox);        TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);        newStack.mStackBox = newBox;        newBox.mStack = newStack;        mHomeStack = newStack;    }

相应在WMS中,每个Display对象都会给他new一个DisplayContent,保存跟这个Display相关的窗体等信息,这点从WMS的构造函数能够看出来。从DisplayContent()构造函数中还能够看出,每个DisplayContent至少包括一个StackBox和TaskStack

createDisplayContentLocked()-->getDisplayContentLocked()-->WMS.newDisplayContentLocked()-->new DisplayContent();

WindowManagerService(){         ............         Display[] displays = mDisplayManager.getDisplays();        for (Display display : displays) {            createDisplayContentLocked(display);        }        ........}

2、mInitialDisplayWidth、mInitialDisplayHeight、mInitialDisplayDensity

保存的是初始屏幕宽度、高度、密度

3、mDisplayInfo

由第1条中的DisplayContent()构造函数中能够看出,mDisplayInfo就是从Display中获取的,保存着Display的相关信息。

4、layoutNeeded

当有窗体须要Layout时,layoutNeeded就会被设为true。

5、mStackBoxes

正常来说mStackBoxes中会保存两个StackBox,一个StackBox(0)里面仅仅包括Launcher,还有一个StackBox包括全部其它窗体。

①StackBox.mParent

    /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this     * is this entire size of mDisplayContent. */
mParent表示由哪个StackBox分裂而来,可是对于StackBox 0和StackBox 1的mParent都为null。

②StackBox.mBounds

WMS.performLayoutLockedInner()-->DisplayContent.setStackBoxSize()-->StackBox.setStackBoxSizes()-->mBounds.set(bounds);

bounds尺寸来源于mPolicy.getContentRectLw(bounds);

    public void getContentRectLw(Rect r) {        r.set(mContentLeft, mContentTop, mContentRight, mContentBottom);    }
对于720*1280尺寸的手机,
(mContentLeft, mContentTop, mContentRight, mContentBottom)=(0,50,720,1280),踢出了状态栏高度,因此mBounds=(0,50,720,1280)
StackBox.mVertical

这个变量表示mFirst 和mSecond分裂方向是否是垂直分裂还是左右分裂,详细见split()函数。

/** Relative orientation of mFirst and mSecond. */

④StackBox.layoutNeeded

⑤StackBox.

⑥StackBox.mStack

/** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */

6、StackBox.split()

StackBox分裂函数,分裂的两个StackBox分别保存在mFirst和mSecond中(二叉树方式分裂)。

    TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {        if (mStackBoxId != relativeStackBoxId) {            if (mStack != null) {                return null;            }            TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);            if (stack != null) {                return stack;            }            return mSecond.split(stackId, relativeStackBoxId, position, weight);        }        TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);        TaskStack firstStack;        TaskStack secondStack;        if (position == TASK_STACK_GOES_BEFORE) {            position = TASK_STACK_TO_LEFT_OF;        } else if (position == TASK_STACK_GOES_AFTER) {            // TODO: Test Configuration here for LTR/RTL.            position = TASK_STACK_TO_RIGHT_OF;        }        switch (position) {            default:            case TASK_STACK_TO_LEFT_OF:            case TASK_STACK_TO_RIGHT_OF:                mVertical = false;                if (position == TASK_STACK_TO_LEFT_OF) {                    mWeight = weight;                    firstStack = stack;                    secondStack = mStack;                } else {                    mWeight = 1.0f - weight;                    firstStack = mStack;                    secondStack = stack;                }                break;            case TASK_STACK_GOES_ABOVE:            case TASK_STACK_GOES_BELOW:                mVertical = true;                if (position == TASK_STACK_GOES_ABOVE) {                    mWeight = weight;                    firstStack = stack;                    secondStack = mStack;                } else {                    mWeight = 1.0f - weight;                    firstStack = mStack;                    secondStack = stack;                }                break;        }        mFirst = new StackBox(mService, mDisplayContent, this);        firstStack.mStackBox = mFirst;        mFirst.mStack = firstStack;        mSecond = new StackBox(mService, mDisplayContent, this);        secondStack.mStackBox = mSecond;        mSecond.mStack = secondStack;        mStack = null;        return stack;    }
分裂的结果仅仅有两种情况:

①分裂节点的StackBox.mStack转移到新的mFirst.mStack中,mSecond.mStack=new TaskStack(mService, stackId, mDisplayContent);

②分裂节点的StackBox.mStack转移到新的mSecond.mStack中,mFirst.mStack=new TaskStack(mService, stackId, mDisplayContent);

上面两种情况共同点是分裂节点StackBox.mStack会置null。

上述代码还能够归纳出,分裂节点就是二叉树的叶节点,仅仅有叶节点才干够分裂,仅仅有叶节点mStack变量才不为null。也能够说一个StackBox叶节点相应一个TaskStack。

从Android4.4源代码来看,眼下默认显示屏DEFAULT_DISPLAY的DisplayContent拥有两棵StackBox二叉树,这两个StackBox二叉树都还没有进行分裂过,仅仅包括一个根节点。

8、TaskStack类

StackBox二叉树树的一个叶节点相应有一个TaskStack。

①TaskStack.mStackId,“stackId The id of the new TaskStack to create.”

②TaskStack.mTasks,保存着这个Task栈(TaskStack)中的全部Task。一个TaskStack中能够包括非常多Task任务。

③TaskStack.mDimLayer、TaskStack.mAnimationBackgroundSurface

DimLayer对象,用来实现阴影效果的Surface包装类对象,弹出不论什么dialog,理应将dialog之下的窗体上面加一个阴影,也就是将dialog设置一个WindowManager.LayoutParams.FLAG_DIM_BEHIND属性mAnimationBackgroundSurface跟背景动画相关。

TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {        mService = service;        mStackId = stackId;        mDisplayContent = displayContent;        mDimLayer = new DimLayer(service, this);        mAnimationBackgroundSurface = new DimLayer(service, this);    }

④TaskStack.mDimWinAnimator

保存着阴影效果Surface的窗体动画,在startDimmingIfNeeded()函数中更新WindowStateAnimator。

void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {        // Only set dim params on the highest dimmed layer.        final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator;        // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.        if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null                || !existingDimWinAnimator.mSurfaceShown                || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {            mDimWinAnimator = newWinAnimator;        }    }
mDimWinAnimator中保存的动画与其它窗体的动画是同一个对象,并不独立拥有WindowStateAnimator

⑤TaskStack.mAnimationBackgroundSurface

⑥TaskStack.mAnimationBackgroundAnimator

上面两个跟背景动画相关?

9、mTaskHistory

保存着全部TaskStack中的Task合集。

10、mExitingTokens、mExitingAppTokens

mExitingTokens:* Window tokens that are in the process of exiting, but still on screen for animations.*

mExitingAppTokens: * Application tokens that are in the process of exiting, but still on screen for animations.*

相应延迟remove的WindowToken、AppWindowToken分别保存在mExitingTokens和mExitingAppTokens中。在下一次调用performLayoutAndPlaceSurfacesLockedInner()时便从这两个list中移除满足一定条件的Token。

11、mWindows

保存着属于该DisplayContent的按Z轴高度排列的全部WindowState。

12、createStack()

函数用来创建一个TaskStack。

TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {        TaskStack newStack = null;        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="                + relativeStackBoxId + " position=" + position + " weight=" + weight);        if (stackId == HOME_STACK_ID) {            if (mStackBoxes.size() != 1) {                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");            }            newStack = mHomeStack;        } else {            int stackBoxNdx;            for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {                final StackBox box = mStackBoxes.get(stackBoxNdx);                if (position == StackBox.TASK_STACK_GOES_OVER                        || position == StackBox.TASK_STACK_GOES_UNDER) {                    // Position indicates a new box is added at top level only.                    if (box.contains(relativeStackBoxId)) {                        StackBox newBox = new StackBox(mService, this, null);                        newStack = new TaskStack(mService, stackId, this);                        newStack.mStackBox = newBox;                        newBox.mStack = newStack;                        final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;                        if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +                                (stackBoxNdx + offset));                        mStackBoxes.add(stackBoxNdx + offset, newBox);                        break;                    }                } else {                    // Remaining position values indicate a box must be split.                    newStack = box.split(stackId, relativeStackBoxId, position, weight);                    if (newStack != null) {                        break;                    }                }            }            if (stackBoxNdx < 0) {                throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId                        + " not found.");            }        }        if (newStack != null) {            layoutNeeded = true;        }        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,                (int)(weight * 100 + 0.5));        return newStack;    }

position大体上分为两大类型,导致有两种创建TaskStack方式:①直接new一棵仅仅有根节点的StackBox树,再new一个TaskStack;②从StackBox.mStackBoxId==relativeStackBoxId的叶节点上分裂出两个StackBox,再new一个TaskStack保存在两个中的一个StackBox中。眼下看来android4.4的第二个TaskStack是通过第一种方式创建的。

ActivityStackSupervisor.startActivityUncheckedLocked()-->ActivityStackSupervisor.adjustStackFocus()-->ActivityManagerService.createStack(-1, HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f);研究下这串代码调用会发现AMS那边相应会new ActivityStack,也就是说AMS中的一个ActivityStack相应WMS中的一个TaskStack,且是一一相应关系。这样的相应关系体如今TaskStack.mStackId==ActivityStack.mStackId。

13、moveHomeStackBox()

从名字就能够看出是干嘛的,移动Home相应的StackBox函数。mStackBoxes中有序的保存着StackBox二叉树根节点,因此肯定会有调换顺序函数,这个函数就是。从moveHomeStackBox()函数中还能够知道眼下仅仅支持两颗StackBox树。

boolean moveHomeStackBox(boolean toTop) {        if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +                Debug.getCallers(4));        EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);        switch (mStackBoxes.size()) {            case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");            case 1: return false; // Only the home StackBox exists.            case 2:                if (homeOnTop() ^ toTop) {                    mStackBoxes.add(mStackBoxes.remove(0));                    return true;                }                return false;            default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");        }    }

14、setTouchExcludeRegion()

这个函数主要作用是设置目标TaskStack的触摸区域mTouchExcludeRegion值,为多窗体设计的。

WMS.performLayoutAndPlaceSurfacesLockedInner()-->WMS.setFocusedStackFrame()-->setTouchExcludeRegion()

16、switchUserStacks()

这个函数在多用户切换时调用。

void switchUserStacks(int oldUserId, int newUserId) {        final WindowList windows = getWindowList();        for (int i = 0; i < windows.size(); i++) {            final WindowState win = windows.get(i);            if (win.isHiddenFromUserLocked()) {                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "                        + win.mOwnerUid);                win.hideLw(false);            }        }        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {            mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);        }    }
函数调用isHiddenFromUserLocked()推断窗体是否可以在新用户中显示,返回true就调用WindowState.hideLw()隐藏窗体。
同一时候会调用StackBox.switchUserStacks()-->TaskStack.switchUser(),可是这个
switchUser()逻辑有问题吧??

void switchUser(int userId) {        int top = mTasks.size();        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {            Task task = mTasks.get(taskNdx);            if (task.mUserId == userId) {                mTasks.remove(taskNdx);                mTasks.add(task);                --top;            }        }    }

完。

转载于:https://www.cnblogs.com/mengfanrong/p/4022780.html

你可能感兴趣的文章
Android 设置界面的圆角选项
查看>>
百度地图api服务端根据经纬度得到地址
查看>>
css经典布局——头尾固定高度中间高度自适应布局
查看>>
CATALAN数 学习
查看>>
jQuery:localStorage用法
查看>>
kindle 3快捷键
查看>>
在VS2013中打开Nuget
查看>>
web攻击几种方法
查看>>
hdu 4350 Card(递推循环节,3级)
查看>>
ajax的使用
查看>>
437.Path Sum III(递归!important!)
查看>>
jQuery找兄弟系列next(),nextAll(),nextUntil(),prev(),prevAll(),prevUntil(),siblings()
查看>>
IntelliJ IDEA的配置优化
查看>>
Day 1 用户交互
查看>>
P1903 [国家集训队]数颜色 / 维护队列
查看>>
【0805作业】模拟多人爬山
查看>>
window.setTimeout() 和 window.setInterval() 使用说明
查看>>
大数据组件
查看>>
ActionResult的其它返回值
查看>>
Mac零散小技巧
查看>>