這篇博客我們分析WMS的一些常用變量,我們依然從主線addWindow開始分析,碰到一些常用的變量再進行分析。
DisplayContent
我們再來看如下DisplayContent 類
final DisplayContent displayContent = getDisplayContentLocked(displayId);
我們再來看getDisplayContentLocked函數,當mDisplayContents沒有對應displayId對應的DisplayContent,會調用newDisplayContentLocked函數創建一個DisplayContent 然後放入mDisplayContents。
- public DisplayContent getDisplayContentLocked(final int displayId) {
- DisplayContent displayContent = mDisplayContents.get(displayId);
- if (displayContent == null) {
- final Display display = mDisplayManager.getDisplay(displayId);
- if (display != null) {
- displayContent = newDisplayContentLocked(display);
- }
- }
- return displayContent;
- }
DisplayContent 的mWindows放了該顯示設備所有的window。WindowManager.LayoutParams token
我們看addWindow這個函數的一個參數WindowManager.LayoutParams attrs,這個參數有很多地方修改,最基本的是在Activity應用中調用setContentView的時候會初始化。
現在我們來看其中一個重要的成員變量token。
先看下面代碼,當該窗口是一個子窗口時,會調用windowForClientLocked來查找主窗口的WindowState。這個WindowState也就是子窗口的attachedWindow。
- if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(null, attrs.token, false);
- if (attachedWindow == null) {
- Slog.w(TAG, "Attempted to add window with token that is not a window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
- && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
- Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
- }
- }
我們來看下windowForClientLocked函數,就是從mWindowMap中獲取其attrs.token的WindowState,說明子窗口的attrs.token放的是其父窗口的token。
- final WindowState windowForClientLocked(Session session, IBinder client,
- boolean throwOnError) {
- WindowState win = mWindowMap.get(client);
- ......
-
- return win;
- }
那我們先來看看這個token是從何而來,
我們知道WMS的addWindow,是用ActivityThread的handleResumeActivity函數調用如下代碼發起的,我們先來看看WindowManagerImpl的addView函數
- if (r.window == null && !a.mFinished && willBeVisible) {
- r.window = r.activity.getWindow();
- View decor = r.window.getDecorView();
- decor.setVisibility(View.INVISIBLE);
- ViewManager wm = a.getWindowManager();
- WindowManager.LayoutParams l = r.window.getAttributes();
- a.mDecor = decor;
- l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
- l.softInputMode |= forwardBit;
- if (a.mVisibleFromClient) {
- a.mWindowAdded = true;
- wm.addView(decor, l);
- }
WindowManagerImpl的addView函數,直接調用了WindowMangerGlobal的addView函數
- @Override
- public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
- applyDefaultToken(params);
- mGlobal.addView(view, params, mDisplay, mParentWindow);
- }
WindowMangerGlobal的addView函數先調用了其parentWindow的adjustLayoutParamsForSubWindow函數,然後就是創建ViewRooImpl對象,再調用其setView函數,就是在這個函數中通過Binder調用了WMS的addWindow函數。
- public void addView(View view, ViewGroup.LayoutParams params,
- Display display, Window parentWindow) {
- if (view == null) {
- throw new IllegalArgumentException("view must not be null");
- }
- if (display == null) {
- throw new IllegalArgumentException("display must not be null");
- }
- if (!(params instanceof WindowManager.LayoutParams)) {
- throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
- }
-
- final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
- if (parentWindow != null) {
- parentWindow.adjustLayoutParamsForSubWindow(wparams);
- }
- ......
-
- root = new ViewRootImpl(view.getContext(), display);
-
- view.setLayoutParams(wparams);
-
- mViews.add(view);
- mRoots.add(root);
- mParams.add(wparams);
- }
-
- // do this last because it fires off messages to start doing things
- try {
- root.setView(view, wparams, panelParentView);
- }
- ......
- }
那我們先要看這個parentWindow是誰,這個parentWindow是在創建WindowManagerImpl 時傳進來的。
- public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
- return new WindowManagerImpl(mDisplay, parentWindow);
- }
這個函數是在Activity的attach中調用的,代碼如下:
- mWindow.setWindowManager(
- (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
- mToken, mComponent.flattenToString(),
- (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
最後我們看傳參是this,就是代表Activity中創建的PhoneWindow對象。
- public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
- boolean hardwareAccelerated) {
- mAppToken = appToken;
- mAppName = appName;
- mHardwareAccelerated = hardwareAccelerated
- || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
- if (wm == null) {
- wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- }
- mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
- }
Window的adjustLayoutParamsForSubWindow函數如下,會把wp的token改成mAppToken。
- void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
- CharSequence curTitle = wp.getTitle();
- if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
- ......
- } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
- .......
- } else {
- if (wp.token == null) {
- wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
- }
- if ((curTitle == null || curTitle.length() == 0)
- && mAppName != null) {
- wp.setTitle(mAppName);
- }
- }
- if (wp.packageName == null) {
- wp.packageName = mContext.getPackageName();
- }
- if (mHardwareAccelerated) {
- wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
- }
而這個mAppToken就是在setWindowManager時賦值的,因此這個token就是Activity的mToken。就是每一個Activity的全局唯一性。
- public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
- boolean hardwareAccelerated) {
- mAppToken = appToken;
- mAppName = appName;
- mHardwareAccelerated = hardwareAccelerated
- || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
- if (wm == null) {
- wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- }
- mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
- }
mTokenMap
我們再回想之前分析的博客,每個Activity啓動的時候會在ActivityStack中調用mWindowManager.addAppToken函數,WMS的addAppToken函數如下,就是放入mTokenMap中,key就是appToken,Value就是APPWindowToken。
- @Override
- public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
- int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
- int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
- ......
-
- synchronized(mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
- if (atoken != null) {
- Slog.w(TAG, "Attempted to add existing app token: " + token);
- return;
- }
- atoken = new AppWindowToken(this, token, voiceInteraction);
- ......
-
- mTokenMap.put(token.asBinder(), atoken);
-
- // Application tokens start out hidden.
- atoken.hidden = true;
- atoken.hiddenRequested = true;
-
- }
- }
繼續回到addWindow函數,下面是一些出錯處理。首先就是傳來的appToken一定要在mTokenMap有對應的WindowToken。
- WindowToken token = mTokenMap.get(attrs.token);
- if (token == null) {
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- Slog.w(TAG, "Attempted to add application window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_INPUT_METHOD) {
- Slog.w(TAG, "Attempted to add input method window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_VOICE_INTERACTION) {
- Slog.w(TAG, "Attempted to add voice interaction window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_WALLPAPER) {
- Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_DREAM) {
- Slog.w(TAG, "Attempted to add Dream window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- if (type == TYPE_ACCESSIBILITY_OVERLAY) {
- Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- token = new WindowToken(this, attrs.token, -1, false);
- addToken = true;
- } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- AppWindowToken atoken = token.appWindowToken;
- if (atoken == null) {
- Slog.w(TAG, "Attempted to add window with non-application token "
- + token + ". Aborting.");
- return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
- } else if (atoken.removed) {
- Slog.w(TAG, "Attempted to add window with exiting application token "
- + token + ". Aborting.");
- return WindowManagerGlobal.ADD_APP_EXITING;
- }
- if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
- // No need for this guy!
- if (localLOGV) Slog.v(
- TAG, "**** NO NEED TO START: " + attrs.getTitle());
- return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
- }
- } else if (type == TYPE_INPUT_METHOD) {
- if (token.windowType != TYPE_INPUT_METHOD) {
- Slog.w(TAG, "Attempted to add input method window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_VOICE_INTERACTION) {
- if (token.windowType != TYPE_VOICE_INTERACTION) {
- Slog.w(TAG, "Attempted to add voice interaction window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_WALLPAPER) {
- if (token.windowType != TYPE_WALLPAPER) {
- Slog.w(TAG, "Attempted to add wallpaper window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_DREAM) {
- if (token.windowType != TYPE_DREAM) {
- Slog.w(TAG, "Attempted to add Dream window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
- if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
- Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "
- + attrs.token + ". Aborting.");
- return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
- }
- } else if (token.appWindowToken != null) {
- Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
- // It is not valid to use an app token with other system types; we will
- // instead make a new token for it (as if null had been passed in for the token).
- attrs.token = null;
- token = new WindowToken(this, null, -1, false);
- addToken = true;
- }
mWindowMap
然後就新建一個WindowState對象,加入到mWindowMap中,注意這裏的key是client.asBinder
- WindowState win = new WindowState(this, session, client, token,
- attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
- ......
- win.attach();
- mWindowMap.put(client.asBinder(), win);
這裏的client,是ViewRootImpl的mWindow 對象用來和WMS通信的,一個ViewRootImpl一個mWindow對象。
mWindow = new W(this);
token.windows
再回到addWindow函數,下面是關於新窗口確定插入的位置的相關代碼:
- if (type == TYPE_INPUT_METHOD) {
- win.mGivenInsetsPending = true;
- mInputMethodWindow = win;
- addInputMethodWindowToListLocked(win);
- imMayMove = false;
- } else if (type == TYPE_INPUT_METHOD_DIALOG) {
- mInputMethodDialogs.add(win);
- addWindowToListInOrderLocked(win, true);
- moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
- imMayMove = false;
- } else {
- addWindowToListInOrderLocked(win, true);
- if (type == TYPE_WALLPAPER) {
- mLastWallpaperTimeoutTime = 0;
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (mWallpaperTarget != null
- && mWallpaperTarget.mLayer >= win.mBaseLayer) {
- // If there is currently a wallpaper being shown, and
- // the base layer of the new window is below the current
- // layer of the target window, then adjust the wallpaper.
- // This is to avoid a new window being placed between the
- // wallpaper and its target.
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- }
- }
我們主要看下addWindowToListInOrderLocked函數,這個函數分有附屬窗口和沒有附屬窗口,我們先看下有附屬窗口的處理。
- private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
- if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
- " Callers=" + Debug.getCallers(4));
- if (win.mAttachedWindow == null) {
- final WindowToken token = win.mToken;
- int tokenWindowsPos = 0;
- if (token.appWindowToken != null) {
- tokenWindowsPos = addAppWindowToListLocked(win);
- } else {
- addFreeWindowToListLocked(win);
- }
- if (addToToken) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
- token.windows.add(tokenWindowsPos, win);
- }
- } else {
- addAttachedWindowToListLocked(win, addToToken);
- }
-
- if (win.mAppToken != null && addToToken) {
- win.mAppToken.allAppWindows.add(win);
- }
- }
addAttachedWindowToListLocked函數,先調用getTokenWindowsOnDisplay函數,來得到所有這個WindowToken的WindowState,然後根據這個WindowState插入合適位置。並且把要插入的windowState,也放入token.windows。
- private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
- final WindowToken token = win.mToken;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent == null) {
- return;
- }
- final WindowState attached = win.mAttachedWindow;
-
- WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
-
- // Figure out this window's ordering relative to the window
- // it is attached to.
- final int NA = tokenWindowList.size();
- final int sublayer = win.mSubLayer;
- int largestSublayer = Integer.MIN_VALUE;
- WindowState windowWithLargestSublayer = null;
- int i;
- for (i = 0; i < NA; i++) {
- WindowState w = tokenWindowList.get(i);
- final int wSublayer = w.mSubLayer;
- if (wSublayer >= largestSublayer) {
- largestSublayer = wSublayer;
- windowWithLargestSublayer = w;
- }
- if (sublayer < 0) {
- // For negative sublayers, we go below all windows
- // in the same sublayer.
- if (wSublayer >= sublayer) {
- if (addToToken) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
- token.windows.add(i, win);//放入WindowToken的windows
- }
- placeWindowBefore(wSublayer >= 0 ? attached : w, win);//插入合適位置
- break;
- }
- } else {
- // For positive sublayers, we go above all windows
- // in the same sublayer.
- if (wSublayer > sublayer) {
- if (addToToken) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
- token.windows.add(i, win);
- }
- placeWindowBefore(w, win);
- break;
- }
- }
- }
- if (i >= NA) {
- if (addToToken) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token);
- token.windows.add(win);
- }
- if (sublayer < 0) {
- placeWindowBefore(attached, win);
- } else {
- placeWindowAfter(largestSublayer >= 0
- ? windowWithLargestSublayer
- : attached,
- win);
- }
- }
- }
我們先看下getTokenWindowsOnDisplay函數,就是遍歷WindowToken的windows,是得同一個DisplayContent對象。
- WindowList getTokenWindowsOnDisplay(WindowToken token, DisplayContent displayContent) {
- final WindowList windowList = new WindowList();
- final int count = token.windows.size();
- for (int i = 0; i < count; i++) {
- final WindowState win = token.windows.get(i);
- if (win.getDisplayContent() == displayContent) {
- windowList.add(win);
- }
- }
- return windowList;
- }
DisplayContent的mWindows
再來看placeWindowBefore函數,插入到windows的pos位置
- private void placeWindowBefore(WindowState pos, WindowState window) {
- final WindowList windows = pos.getWindowList();
- int i = windows.indexOf(pos);
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
- TAG, "Adding window " + window + " at "
- + i + " of " + windows.size() + " (before " + pos + ")");
- if (i < 0) {
- Slog.w(TAG, "placeWindowBefore: Unable to find " + pos + " in " + windows);
- i = 0;
- }
- windows.add(i, window);
- mWindowsChanged = true;
- }
getWindowList就是返回DisplayContent 得到mWindows,所以在placeWindowBefore插入window,最終也都是插入DisplayContent的mWindows
- WindowList getWindowList() {
- final DisplayContent displayContent = getDisplayContent();
- return displayContent == null ? null : displayContent.getWindowList();
- }
繼續看addWindowToListInOrderLocked函數,對沒有附屬窗口的調用addAppWindowToListLocked,就是調用WindowState的getWindowList來獲取displayContent.getWindowList,然後調用placeWindowBefore插入合適的位置。
- private int addAppWindowToListLocked(final WindowState win) {
- final IWindow client = win.mClient;
- final WindowToken token = win.mToken;
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent == null) {
- // It doesn't matter this display is going away.
- return 0;
- }
-
- final WindowList windows = win.getWindowList();
- final int N = windows.size();
- WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
- int tokenWindowsPos = 0;
- int windowListPos = tokenWindowList.size();
- if (!tokenWindowList.isEmpty()) {
- // If this application has existing windows, we
- // simply place the new window on top of them... but
- // keep the starting window on top.
- if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
- // Base windows go behind everything else.
- WindowState lowestWindow = tokenWindowList.get(0);
- placeWindowBefore(lowestWindow, win);
- ......
- }
- }
- }
Task TaskStack
我們再來看看WMS的addAppToken函數,這個函數中新建了APPWindowToken之後,會看mTaskIdToTask是否有這個taskId,沒有會調用createTaskLocked根據AMS傳進來的taskId和stackId創建Task和TaskStack。
- <code class=“language-cpp”> AppWindowToken atoken = findAppWindowToken(token.asBinder());
- if (atoken != null) {
- Slog.w(TAG, ”Attempted to add existing app token: ” + token);
- return;
- }
- atoken = new AppWindowToken(this, token, voiceInteraction);
- ……
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- task = createTaskLocked(taskId, stackId, userId, atoken);
- }
- task.addAppToken(addPos, atoken);
- mTokenMap.put(token.asBinder(), atoken);</code>
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
- if (atoken != null) {
- Slog.w(TAG, "Attempted to add existing app token: " + token);
- return;
- }
- atoken = new AppWindowToken(this, token, voiceInteraction);
- ......
-
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- task = createTaskLocked(taskId, stackId, userId, atoken);
- }
- task.addAppToken(addPos, atoken);
-
- mTokenMap.put(token.asBinder(), atoken);
createTaskLocked函數如下,TaskStack會在ActivityStackSupervisor中調用WMS的attachStack函數創建,這裏然後創建Task,再把task放入mTaskIdToTask中。再把task加入到TaskStack中。
- private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken) {
- if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
- + " atoken=" + atoken);
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null) {
- throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
- }
- EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
- Task task = new Task(taskId, stack, userId, this);
- mTaskIdToTask.put(taskId, task);
- stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
- return task;
- }
WMS的attachStack函數如下,當mStackIdToStack沒有這個stackId,這個時候新建TaskStack,然後加入到mStackIdToStack。
- public void attachStack(int stackId, int displayId) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mWindowMap) {
- final DisplayContent displayContent = mDisplayContents.get(displayId);
- if (displayContent != null) {
- TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null) {
- if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);
- stack = new TaskStack(this, stackId);//新建TaskStack
- mStackIdToStack.put(stackId, stack);//加入到mStackIdToStack
- }
- stack.attachDisplayContent(displayContent);
- displayContent.attachStack(stack);
- moveStackWindowsLocked(displayContent);
- final WindowList windows = displayContent.getWindowList();
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- windows.get(winNdx).reportResized();
- }
- }
- }
AppWindowToken 的mTask
我們再回到WMS的addAppToken函數,創建完task,之後調用了Task的addAppToken函數
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- task = createTaskLocked(taskId, stackId, userId, atoken);
- }
- task.addAppToken(addPos, atoken);
Task的addAppToken把AppWindowToken 放入到Task的mAppTokens中,並且賦值AppWindowToken 的mTask
- void addAppToken(int addPos, AppWindowToken wtoken) {
- final int lastPos = mAppTokens.size();
- if (addPos >= lastPos) {
- addPos = lastPos;
- } else {
- for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
- if (mAppTokens.get(pos).removed) {
- // addPos assumes removed tokens are actually gone.
- ++addPos;
- }
- }
- }
- mAppTokens.add(addPos, wtoken);
- wtoken.mTask = this;
- mDeferRemoval = false;
- }