1、findDesiredInputMethodWindowIndexLocked()
从名字可以出来,这个函数是寻找InputMethodWindow要放置的位置,分析这个函数后自然就知道对于输入法窗口的排列规则。
int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
// TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
// same display. Or even when the current IME/target are not on the same screen as the next
// IME/target. For now only look for input windows on the main screen.
WindowList windows = getDefaultWindowListLocked();
WindowState w = null;
int i;
for (i = windows.size() - 1; i >= 0; --i) { //①从窗口列表的最顶端开始遍历窗口列表,如果该窗口可以成为IME Target,那么该循环退出,即遍历出第一个输入法目标窗口保存在W中,w也可能是mWindows[0];什么情况下窗口才可以成为IME的Target呢?情况一:窗口属性都没有设置FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM属性;情况二:窗口属性同时设置了FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM属性;情况三:TYPE_APPLICATION_STARTING类型窗口也可以作为IME的Target;
WindowState win = windows.get(i);
if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
+ " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
if (canBeImeTarget(win)) { //②如果遍历到一个窗口可以作为IME 的Target,正常情况下那么该Target之上的窗口位置便是输入法位置,特殊情况便是下面那些矫正逻辑,不必太过关心;
w = win;
//Slog.i(TAG, "Putting input method here!");
// Yet more tricksyness! If this window is a "starting"
// window, we do actually want to be on top of it, but
// it is not -really- where input will go. So if the caller
// is not actually looking to move the IME, look down below
// for a real window to target...
if (!willMove
&& w.mAttrs.type == TYPE_APPLICATION_STARTING
&& i > 0) {
WindowState wb = windows.get(i-1);
if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
i--;
w = wb;
}
}
break;
}
}
// Now w is either mWindows[0] or an IME (or null if mWindows is empty).
if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG, "Proposed new IME target: " + w);
// Now, a special case -- if the last target's window is in the
// process of exiting, and is above the new target, keep on the
// last target to avoid flicker. Consider for example a Dialog with
// the IME shown: when the Dialog is dismissed, we want to keep
// the IME above it until it is completely gone so it doesn't drop
// behind the dialog or its full-screen scrim.
final WindowState curTarget = mInputMethodTarget;
if (curTarget != null
&& curTarget.isDisplayedLw()
&& curTarget.isClosing()
&& (w == null || curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) {
if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, not changing");
return windows.indexOf(curTarget) + 1;
}
if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target="
+ w + " willMove=" + willMove);
if (willMove && w != null) {
AppWindowToken token = curTarget == null ? null : curTarget.mAppToken;
if (token != null) {
// Now some fun for dealing with window animations that
// modify the Z order. We need to look at all windows below
// the current target that are in this app, finding the highest
// visible one in layering.
WindowState highestTarget = null;
int highestPos = 0;
if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) {
WindowList curWindows = curTarget.getWindowList();
int pos = curWindows.indexOf(curTarget);
while (pos >= 0) {
WindowState win = curWindows.get(pos);
if (win.mAppToken != token) {
break;
}
if (!win.mRemoved) {
if (highestTarget == null || win.mWinAnimator.mAnimLayer >
highestTarget.mWinAnimator.mAnimLayer) {
highestTarget = win;
highestPos = pos;
}
}
pos--;
}
}
if (highestTarget != null) {
if (DEBUG_INPUT_METHOD) Slog.v(TAG, mAppTransition + " " + highestTarget
+ " animating=" + highestTarget.mWinAnimator.isAnimating()
+ " layer=" + highestTarget.mWinAnimator.mAnimLayer
+ " new layer=" + w.mWinAnimator.mAnimLayer);
if (mAppTransition.isTransitionSet()) {
// If we are currently setting up for an animation,
// hold everything until we can find out what will happen.
mInputMethodTargetWaitingAnim = true;
mInputMethodTarget = highestTarget;
return highestPos + 1;
} else if (highestTarget.mWinAnimator.isAnimating() &&
highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) {
// If the window we are currently targeting is involved
// with an animation, and it is on top of the next target
// we will be over, then hold off on moving until
// that is done.
mInputMethodTargetWaitingAnim = true;
mInputMethodTarget = highestTarget;
return highestPos + 1