WindowManagerService的主要两大作用:
1 和surfaceflinger交互,创建surface, 通知surfacelinger窗口的层级、大小、位置等属性。
2 和inputflinger交互, 告知inputflinger当前窗口大小位置,是否可以接受input事件以及窗口可以处理什么类型的事件。

surfacelinger和inputflinger都是系统里面两个负载较重的服务。为了分析WindowManagerService我准备先从inputflinger这端着手,因为这端相对比较容易,采用自顶向下的方式来进行分析。所以今天先看下inputflinger如何将根据WMS告知的窗口情况来派发input事件。

dumpsys是比较好的工具,我们此次不考虑WMS如何告知inputflinger窗口情况,只关心inputflinger如何根据窗口情况派发输入事件。下面是我在桌面启动了一个全屏应用的()场景,使用adb shell dumpsys input 输出如下:

Input Dispatcher State:DispatchEnabled: 1DispatchFrozen: 0FocusedApplication: name='AppWindowToken{9ab95fe token=Token{867fdb9 ActivityRecord{c189380 u0 com.android.contacts/.activities.CompactContactEditorActivity t6}}}', dispatchingTimeout=5000.000msFocusedWindow: name='Window{c7ac47b u0 com.android.contacts/com.android.contacts.activities.CompactContactEditorActivity}'TouchStates: <no displays touched>Windows:0: name='Window{6887dc9 u0 NavigationBar}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x01840068, type=0x000007e3, layer=211000, frame=[0,432][320,480], scale=1.000000, touchableRegion=[0,432][320,480], inputFeatures=0x00000000, ownerPid=1408, ownerUid=10016, dispatchingTimeout=5000.000ms1: name='Window{7d5502a u0 StatusBar}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x81840048, type=0x000007d0, layer=161000, frame=[0,0][320,24], scale=1.000000, touchableRegion=[0,0][320,24], inputFeatures=0x00000000, ownerPid=1408, ownerUid=10016, dispatchingTimeout=5000.000ms2: name='Window{25377a1 u0 KeyguardScrim}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01110900, type=0x000007ed, layer=141000, frame=[0,0][320,432], scale=1.000000, touchableRegion=[0,0][320,432], inputFeatures=0x00000000, ownerPid=1303, ownerUid=1000, dispatchingTimeout=5000.000ms3: name='Window{3dc7d4 u0 AssistPreviewPanel}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01000118, type=0x000007f1, layer=41000, frame=[0,432][320,432], scale=1.000000, touchableRegion=<empty>, inputFeatures=0x00000000, ownerPid=1408, ownerUid=10016, dispatchingTimeout=5000.000ms4: name='Window{c7ac47b u0 com.android.contacts/com.android.contacts.activities.CompactContactEditorActivity}', displayId=0, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x81810120, type=0x00000001, layer=21015, frame=[0,0][320,480], scale=1.000000, touchableRegion=[0,0][320,480], inputFeatures=0x00000000, ownerPid=1993, ownerUid=10002, dispatchingTimeout=5000.000ms5: name='Window{a245c67 u0 com.android.contacts/com.android.contacts.activities.PeopleActivity}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x81810120, type=0x00000001, layer=21010, frame=[0,0][320,480], scale=1.000000, touchableRegion=[0,0][320,480], inputFeatures=0x00000000, ownerPid=1993, ownerUid=10002, dispatchingTimeout=5000.000ms6: name='Window{e911fed u0 com.android.launcher/com.android.launcher2.Launcher}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01910120, type=0x00000001, layer=21005, frame=[0,0][320,432], scale=1.000000, touchableRegion=[0,0][320,480], inputFeatures=0x00000000, ownerPid=1601, ownerUid=10008, dispatchingTimeout=5000.000ms7: name='Window{5df78f9 u0 com.android.systemui.ImageWallpaper}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00000318, type=0x000007dd, layer=21000, frame=[0,0][960,800], scale=1.000000, touchableRegion=[0,0][960,800], inputFeatures=0x00000000, ownerPid=1408, ownerUid=10016, dispatchingTimeout=5000.000ms

输出中windows的信息都来自InputDispatcher的成员变量mWindowHandles,数据结构第一如下

Vector<sp<InputWindowHandle> > mWindowHandles;

mWindowHandles为数组结构,每个元素为一个InputWindowHandle结构,代表一个窗口, 这些InputWindowHandle是Wms告诉inputflinger的,按照z-order从高到低的顺序存储在mWindowHandles数组中。每个InputWindowHandle的成员变量mInfo 描述了window的一些情况。mInfo的类型为InputWindowInfo:

struct InputWindowInfo {sp<InputChannel> inputChannel; // 事件派发通道String8 name;   // window 名称int32_t layoutParamsFlags;  // flagsint32_t layoutParamsType;  // 类型nsecs_t dispatchingTimeout; // anr超时时间int32_t frameLeft;  // 坐标int32_t frameTop;int32_t frameRight;int32_t frameBottom; float scaleFactor;  // 缩放Region touchableRegion; // 可触摸区域bool visible;   // 是否可见bool canReceiveKeys;  // 是否可以接收key时间bool hasFocus;  // 是否是焦点window (默认key事件发给焦点window)bool hasWallpaper;  // 是否能显示壁纸bool paused;  // 是否处于暂停状态int32_t layer;  // layer 也就是层级z-orderint32_t ownerPid;  // 所属应用进程的pidint32_t ownerUid; // 所属应用进程的uidint32_t inputFeatures; // 支持的featureint32_t displayId;   // 所属的屏幕(display) id
}

layoutParamsFlags变量描述了window能处理哪些事件。frameLeft、frameTop、frameRight、frameBottom、scaleFactor、touchableRegion描述了window的坐标,一般情况下window只能处理落在自身范围内的输入事件。visible则表示window是否可见,不可见的window也不能处理input事件。hasFocus变量则表示window是否是焦点window,一般key事件都发送到焦点window。displayId则用于标识window所属的屏幕(display),window只处理落在自己屏幕上的input事件。有了这些背景只是我们来分析代码实现。

对于一个MotionEvent 可以能处理该事件的Window并不是只有焦点窗口,因为Window有一些特殊的layoutParamsFlags可以,可以用于接收到触摸到window外部的事件,我们比较熟悉的PopupWindow.setOutsideTouchable(boolean touchable)就会设置一个比较特殊的layoutParamsFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH)。设置该参数的Flags就会收到点击到Window外部的事件。 另外Dialog也有一个函数Dialog.setCanceledOnTouchOutside(boolean cancel) 函数如果参数cancel为true,那么input系统就会把不在Dialog window范围内的事件发送给它,这是通过window的layoutParamsFlags另外一个表示WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL实现的。
下面我列出几个在window事件处理中比较常见的flag。这些flag都是WindowManager.LayoutParams下的常亮。

FLAG 描述
FLAG_NOT_FOCUSABLE 该标志表示window不会获取焦点,不接收key事件
FLAG_NOT_TOUCHABLE 该标志表示window不会处理touch事件
FLAG_NOT_TOUCH_MODAL 该标志表示该window允许将超出该窗口的事件发送给后面的窗口处理,否则事件不会发送到后面窗口,该窗口会处理所有事件,当设置了FLAG_NOT_FOCUSABLE标志,该标志自动置1
FLAG_WATCH_OUTSIDE_TOUCH 当点击了window外部区域,该window可以收到一个ACTION_OUTSIDE事件

对于真正处理事件的window,对于相同的MotionEvent,假设是一个ACTION_DOWN事件,目标window要收到一个ACTION_DOWN事件,但是其他window可能要收到ACTION_OUTSIDE事件,这样同一个MotionEvent对多个window产生了不同的事件,这是通过给该window一个TargetFlags来实现的,有些TargetFlag是一次性的。关于TargetFlag描述如下:

FLAG 描述
FLAG_DISPATCH_AS_IS 表示序列事件应该一直发送给该window,没有该标志只需要发送一个事件给该window
FLAG_DISPATCH_AS_OUTSIDE 发送一个ACTION_OUTSIDE给该window
FLAG_DISPATCH_AS_HOVER_EXIT 发送一个ACTION_HOVER_EXIT事件给该window
FLAG_DISPATCH_AS_HOVER_ENTER 发送一个ACTION_HOVER_ENTER给该window
FLAG_DISPATCH_AS_SLIPPERY_EXIT 发送一个ACTION_CANCEL给该window
FLAG_DISPATCH_AS_SLIPPERY_ENTER 发送一个ACTION_DOWN给该window

除了上述知识点外,我们还有一点需要理解,一个Motion事件序列一般是: ACTION_DOWN->一系列ACTION_MOVE->ACTION_UP|ACTION_CANCEL。一般在收到ACTION_DOWN的时候确定目标window,后续ACTION_MOVE和ACTION_UP|ACTION_CANCEL事件都应该发送给该窗口,即使我们的ACTION_MOVE已经超出了该window的范围也应该将该事件派发给该window,所以一般确定派发window的在序列事件开始的地方。

下面我们来通过代码来详细解读Input系统如何选择目标窗口,代码是InputDispatcher的findTouchdWindowTargetsLocked
frameworks/native/services/inputflinger/InputDispatcher.cpp

1129 int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
1130         const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
1131         bool* outConflictingPointerActions) {1132     enum InjectionPermission {1133         INJECTION_PERMISSION_UNKNOWN,
1134         INJECTION_PERMISSION_GRANTED,
1135         INJECTION_PERMISSION_DENIED
1136     };
1137
1138     nsecs_t startTime = now();
1139
1140     // For security reasons, we defer updating the touch state until we are sure that
1141     // event injection will be allowed.
1142     int32_t displayId = entry->displayId;
1143     int32_t action = entry->action;
1144     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
1145
1146     // Update the touch state as needed based on the properties of the touch event.
1147     int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
1148     InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
1149     sp<InputWindowHandle> newHoverWindowHandle;
1150
1151     // Copy current touch state into mTempTouchState.
1152     // This state is always reset at the end of this function, so if we don't find state
1153     // for the specified display then our initial state will be empty.
1154     const TouchState* oldState = NULL;
1155     ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
1156     if (oldStateIndex >= 0) {1157         oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex);// 复制屏幕处理input事件的状态到mTempTouchState中
1158         mTempTouchState.copyFrom(*oldState);
1159     }
1160
1161     bool isSplit = mTempTouchState.split;
1162     bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0
1163             && (mTempTouchState.deviceId != entry->deviceId
1164                     || mTempTouchState.source != entry->source
1165                     || mTempTouchState.displayId != displayId);
1166     bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
1167             || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
1168             || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
1169     bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
1170             || maskedAction == AMOTION_EVENT_ACTION_SCROLL
1171             || isHoverAction);
1172     bool wrongDevice = false;
1173     if (newGesture) {// 对于新的操作序列开始,清空旧的事件处理状态mTempTouchState。
1174         bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
1175         if (switchedDevice && mTempTouchState.down && !down) {1176 #if DEBUG_FOCUS
1177             ALOGW("Dropping event because a pointer for a different device is already down.");
1178 #endif
1179             injectionResult = INPUT_EVENT_INJECTION_FAILED;
1180             switchedDevice = false;
1181             wrongDevice = true;
1182             goto Failed;
1183         }
1184         mTempTouchState.reset();
1185         mTempTouchState.down = down;
1186         mTempTouchState.deviceId = entry->deviceId;
1187         mTempTouchState.source = entry->source;
1188         mTempTouchState.displayId = displayId;
1189         isSplit = false;
1190     }
1191
1192     if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {1193         /* Case 1: New splittable pointer going down, or need target for hover or scroll. */// case 1 处理新的操作序列开始,对于当前操作状态为isSplit的状态的情况,AMOTION_EVENT_ACTION_POINTER_DOWN// 函数将被当新操作序列开始处理......
1285     } else {1286         /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */// case 2: mov,up,或者cancel或者pointer down事件,应该发送给之前处理case1的对应window上。......
1341     }

findTouchedWindowTargetsLocked函数比较长我们分段去看,函数的参数currentTime表示当前时间,entry表示要派发的input事件,这里类型为MotionEntry表示为触摸事件。inputTargets是一个输出变量,用于保存最终要处理该事件(entry)对应的window集合。nextWakeupTime也是一个输出变量,用于通知InputDispatcher没有事件处理的时候休眠多久。outConflictingPointerActions也是一个输出变量,用于反馈上级函数当前事件是否有冲突。

对于input事件的处理Android要维护一个状态,要根据当前状态去处理下一个事件。比如我们的一次滑动事件,起始位置落在了普通应用的窗口上,但是我们一直向上滑动,一直滑动到statusbar所在的位置,那么这个事件应该继续派发给普通应用程序而不应该派发给statusbar,因为我们需要事件的连续性,即使statusbar在普通应用窗口上面。 为了实现这个功能就需要做动作序列的追踪。Android的InputDispatcher为每个屏幕创建一个TouchState变量来追踪落在该屏幕的序列事件状态。

    struct TouchState {bool down;bool split;int32_t deviceId; // id of the device that is currently down, others are rejecteduint32_t source;  // source of the device that is current down, others are rejectedint32_t displayId; // id to the display that currently has a touch, others are rejected}

down 表示该屏幕已经开始处理一个事件序列(一个input序列一般开始于down事件结束于up或者cancel)。deviceId、source、displayId都是down事件对应的设备信息。split表示当前屏幕上AMOTION_EVENT_ACTION_POINTER_DOWN事件应当当做一个事件序列的开始来处理。当前屏幕上有接受input事件的窗口包含WindowManager.FLAG_SPLIT_TOUCH标志,就会设置split为true。 FLAG_SPLIT_TOUCH这个flag的描述如下:
frameworks/base/core/java/android/view/WindowManager.java

     /** Window flag: when set the window will accept for touch events* outside of its bounds to be sent to other windows that also* support split touch.  When this flag is not set, the first pointer* that goes down determines the window to which all subsequent touches* go until all pointers go up.  When this flag is set, each pointer* (not necessarily the first) that goes down determines the window* to which all subsequent touches of that pointer will go until that* pointer goes up thereby enabling touches with multiple pointers* to be split across multiple windows.*/public static final int FLAG_SPLIT_TOUCH = 0x00800000;

也就是说AMOTION_EVENT_ACTION_POINTER_DOWN(支持多点触控的屏幕第二个手指落下就会上报该事件)事件将会重新选择派发的window。

回到findTouchedWindowTargetsLocked函数,首先1155-1159行代码找到当前屏幕处理事件序列的状态,保存在mTempTouchState中。
1161-1172行代码isSplit表示该屏幕上有可以接收input事件的window是否设置了WindowManager.FLAG_SPLIT_TOUCH标志,如果isSplit为true后面需要为AMOTION_EVENT_ACTION_POINTER_DOWN事件寻找新的目标window处理。switchedDevice表示新的输入设备的事件,此display应该处理不了,需要丢掉该事件。isHoverAction表示是否是悬停设备(如鼠标)指针的移入移出事件。newGesture表示新的事件序列开始,对于第一个手指落到该设备的情况(ACTION_DOWN),或者鼠标移入移除,或者开始滚动滚轮设备,都被认为是新的事件序列开始。
1173-1190行代码在一个新输入序列的开始的情况下, 如果发生了设备切换,也就是当前display无法处理这个事件,那么直接直接丢掉这个事件。否则的话新事件序列的开始要重置屏幕的TouchState,1184-1189行代码就是用于重置该屏幕的TouchState。

下面1192-1341行代码,分为两个case来找到处理查找处理事件的目标window,case 1的代码为1192-1284行包含两种情况会进入该case1处理:

  • 一个事件序列的开始:hover 、 scroll、AMOTION_EVENT_ACTION_DOWN事件。
  • 拆分多点触控事件的情况下AMOTION_EVENT_ACTION_POINTER_DOWN事件。

case2的代码为1286-1341行,case2表示该事件序列的前边inpu事件已经找到目标处理窗口,后续事件也应该使用该窗口来处理。包含两种情况会进入该case2处理:

  • mov、up、cancel 事件。
  • 不拆分多点触控事件的情况下AMOTION_EVENT_ACTION_POINTER_DOWN事件。
    其实case1对应的情况是要寻找新的window作为事件处理的window,而case2的情况是直接使用case1中找到的window作为目标窗口。case1对应的事件为一个事件序列的开始,case2对应事件序列开始之后后续事件的处理。

下面我们就按照这两个case,首先来看case1的处理:

1193         /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
1194
1195         int32_t pointerIndex = getMotionEventActionPointerIndex(action);
1196         int32_t x = int32_t(entry->pointerCoords[pointerIndex].
1197                 getAxisValue(AMOTION_EVENT_AXIS_X));
1198         int32_t y = int32_t(entry->pointerCoords[pointerIndex].
1199                 getAxisValue(AMOTION_EVENT_AXIS_Y));
1200         sp<InputWindowHandle> newTouchedWindowHandle;
1201         bool isTouchModal = false;
1202
1203         // Traverse windows from front to back to find touched window and outside targets.
1204         size_t numWindows = mWindowHandles.size();
1205         for (size_t i = 0; i < numWindows; i++) {1206             sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
1207             const InputWindowInfo* windowInfo = windowHandle->getInfo();
1208             if (windowInfo->displayId != displayId) {1209                 continue; // wrong display
1210             }
1211
1212             int32_t flags = windowInfo->layoutParamsFlags;
1213             if (windowInfo->visible) { // 窗口可见
1214                 if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { // 窗口可以接收touch事件
1215                     isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
1216                             | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
1217                     if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { // 该窗口可以消费掉所有后面窗口的事件 或者 // 点击到了窗口区可接收触摸事件区域 那么该窗口为前台窗口,后面的窗口将无法接收// touch event。保存在newTouchedWindowHandle中,该窗口为事件处主理窗口,后面// 我们叫它前台窗口( foreground window)
1218                         newTouchedWindowHandle = windowHandle;
1219                         break; // found touched window, exit window loop
1220                     }
1221                 }
1222
1223                 if (maskedAction == AMOTION_EVENT_ACTION_DOWN
1224                         && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {// 在事件处理窗口之上的窗口,如果设置了FLAG_WATCH_OUTSIDE_TOUCH标志,则对于// AMOTION_EVENT_ACTION_DOWN事件,需要发送给该窗口一个ACTION_OUTSIDE或者// ACTION_PARTIALLY_OBSCURED事件通知该窗口点击其他窗口的通知。
1225                     int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
1226                     if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {1227                         outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
1228                     } else if (isWindowObscuredLocked(windowHandle)) {1229                         outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
1230                     }
1231 // 添加该窗口到mTempTouchState,用于后续事件派发
1232                     mTempTouchState.addOrUpdateWindow(
1233                             windowHandle, outsideTargetFlags, BitSet32(0));
1234                 }
1235             }
1236         }
1237
1238         // Figure out whether splitting will be allowed for this window.
1239         if (newTouchedWindowHandle != NULL
1240                 && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {1241             // New window supports splitting.// 前台窗口包含需要拆分多点触控事件,设置isSplit为真
1242             isSplit = true;
1243         } else if (isSplit) {1244             // New window does not support splitting but we have already split events.
1245             // Ignore the new window.// 新找到的前台窗口不能处理拆分多点触控事件,则设置为null
1246             newTouchedWindowHandle = NULL;
1247         }
1248
1249         // Handle the case where we did not find a window.
1250         if (newTouchedWindowHandle == NULL) {1251             // Try to assign the pointer to the first foreground window we find, if there is one.// 如果没有找到前台窗口,则尝试使用之前的前台窗口,没有的话则拒绝派发该事件
1252             newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
1253             if (newTouchedWindowHandle == NULL) {1254                 ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
1255                 injectionResult = INPUT_EVENT_INJECTION_FAILED;
1256                 goto Failed;
1257             }
1258         }
1259 // 设置targetFlags表示该窗口需要发送什么事件给应用。
1260         // Set target flags.
1261         int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
1262         if (isSplit) {1263             targetFlags |= InputTarget::FLAG_SPLIT;
1264         }
1265         if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {1266             targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
1267         } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {1268             targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
1269         }
1270
1271         // Update hover state.
1272         if (isHoverAction) {1273             newHoverWindowHandle = newTouchedWindowHandle;
1274         } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {1275             newHoverWindowHandle = mLastHoverWindowHandle;
1276         }
1277
1278         // Update the temporary touch state.
1279         BitSet32 pointerIds;
1280         if (isSplit) {1281             uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
1282             pointerIds.markBit(pointerId);
1283         }// 添加前台窗口和targetFlags到mTempTouchState用于后续事件派发
1284         mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);

针对case 1, 会按照z-order自上而下的遍历window来寻找处理input事件的目标window,要成为目标window要同时满足如下条件:

  • window 可见
  • window不包含InputWindowInfo::FLAG_NOT_TOUCHABLE标志。
  • 点击动作落在了该window区域 或者 该window有设置FLAG_NOT_FOCUSABLE 和InputWindowInfo::FLAG_NOT_TOUCH_MODAL标志。
    条件1 中InputWindowInfo::FLAG_NOT_TOUCHABLE为真表示wndow不能处理touch事件。所以input系统不会把MotionEvent 事件发送给这种类型的window。 在满足条件1 的前提下点击坐标落到window上一定是目标window。另外如果window的标志同时不包含InputWindowInfo::FLAG_NOT_FOCUSABLE| InputWindowInfo::FLAG_NOT_TOUCH_MODAL 标志则该window可以处理没有落在自己可点击区域上面的事件,这种情况input事件也会发送到这个window处理。注意如果找到这样的window,后面的window就不去看了,因为事件不需要派发给后面的window了。我们后面称该window为前台window。
        /** Window flag: even when this window is focusable (its* {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events* outside of the window to be sent to the windows behind it.  Otherwise* it will consume all pointer events itself, regardless of whether they* are inside of the window. */public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;

代码1223-1235行代码,在前台window之上,并且设置了 InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH标志的window,它们关心点击自身外部区域 的input事件。点击了它们后面window的区域手指落下的时候需要发送给它们一个ACTION_OUTSIDE事件或者 ACTION_PARTIALLY_OBSCURED 事件。所以当input事件类型为AMOTION_EVENT_ACTION_DOWN时,需要把这些window挑出来放到mTempTouchState中,并且设置上InputTarget::FLAG_WINDOW_IS_OBSCURED或者InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED标志。
这些window最终会收到相关的input事件。
最后1239-1282行代码对目标window做一些处理添后将该window添加到TouchState中。添加window到TouchState中使用的方法为

mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,int32_t targetFlags, BitSet32 pointerIds) {if (targetFlags & InputTarget::FLAG_SPLIT) {split = true;}for (size_t i = 0; i < windows.size(); i++) {TouchedWindow& touchedWindow = windows.editItemAt(i);if (touchedWindow.windowHandle == windowHandle) {touchedWindow.targetFlags |= targetFlags;if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;}touchedWindow.pointerIds.value |= pointerIds.value;return;}}windows.push();TouchedWindow& touchedWindow = windows.editTop();touchedWindow.windowHandle = windowHandle;touchedWindow.targetFlags = targetFlags;touchedWindow.pointerIds = pointerIds;
}

addOrUpdateWindow 有三个参数,newTouchedWindowHandle表示处理MontionEvent的窗口, targetFlags描述了该窗口该如何处理该MotionEvent,比如InputTarget::FLAG_WINDOW_IS_OBSCURED标志会给该window发送一个ACTION_OUTSIDE事件 。pointerIds 描述了落在该window上多点触控的点。

看完findTouchedWindowTargetsLocked的case1的处理,再来看下case2 的处理,由于case2的目标window比较明确代码也比case1要简单不少:

1286         /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
1287
1288         // If the pointer is not currently down, then ignore the event.
1289         if (! mTempTouchState.down) {// 没有down事件无法进入该状态,move,up,cacel 和 point action都需要TouchStat先进入down状态。
1290 #if DEBUG_FOCUS
1291             ALOGW("Dropping event because the pointer is not down or we previously "
1292                     "dropped the pointer down event.");
1293 #endif
1294             injectionResult = INPUT_EVENT_INJECTION_FAILED;
1295             goto Failed;
1296         }
1297
1298         // Check whether touches should slip outside of the current foreground window.
1299         if (maskedAction == AMOTION_EVENT_ACTION_MOVE
1300                 && entry->pointerCount == 1
1301                 && mTempTouchState.isSlippery()) {// 对于支持拆分多点触控事件的window,需要检查移动事件是否将坐标移动到了目标window之外,// 如果移动到了目标window之外,需要给新的处理该事件的window发送一个ACTION_DOWN事件
1302             int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
1303             int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
1304
1305             sp<InputWindowHandle> oldTouchedWindowHandle =
1306                     mTempTouchState.getFirstForegroundWindowHandle();
1307             sp<InputWindowHandle> newTouchedWindowHandle =
1308                     findTouchedWindowAtLocked(displayId, x, y);
1309             if (oldTouchedWindowHandle != newTouchedWindowHandle
1310                     && newTouchedWindowHandle != NULL) {// 处理该事件的window发生变化,就的window需要接收ACTION_CANCEL事件,给旧的window的// target设置InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT标志,将会发送ACTION_CANCEL// 事件给它
1311 #if DEBUG_FOCUS
1312                 ALOGW("Touch is slipping out of window %s into window %s.",
1313                         oldTouchedWindowHandle->getName().string(),
1314                         newTouchedWindowHandle->getName().string());
1315 #endif
1316                 // Make a slippery exit from the old window.
1317                 mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
1318                         InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
1319 // 设置新的前台窗口FLAG_DISPATCH_AS_SLIPPERY_ENTER标志将是它收到// ACTION_DOWN事件。
1320                 // Make a slippery entrance into the new window.
1321                 if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {1322                     isSplit = true;
1323                 }
1324
1325                 int32_t targetFlags = InputTarget::FLAG_FOREGROUND
1326                         | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
1327                 if (isSplit) {1328                     targetFlags |= InputTarget::FLAG_SPLIT;
1329                 }
1330                 if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {1331                     targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
1332                 }
1333
1334                 BitSet32 pointerIds;
1335                 if (isSplit) {1336                     pointerIds.markBit(entry->pointerProperties[0].id);
1337                 }
1338                 mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
1339             } // 其他情况使用现有mTempTouchState中保存的目标window
1340         }
1341     }

case2 的代码比较简单,1289-1296 行代码对于还没有接收down事件就进到case2的情况是不正常的,也就是事件序列还没开始,就要处理后续事件,所以这里直接拒绝派发该事件。1302-1338行代码大多数情况都不会被执行到,所以默认是使用case 1中计算好的mTempTouchState中的目标窗口来处理事件。
对于1302-1338行代码代码,支持拆分多点触控事件的window,如果要处理的事件是ACTION_MOVE事件,并且该事件落下的点只有一个,那么这种情况下如果ACTION_MOVE事件如果移出了目标window,则需要给目标window发送一个ACTION_CANCEL事件,表示该事件移除了window,还要找到能处理该事件的下一个window,如果可以找的到,则需要将ACTION_MOVE事件变为ACTION_DOWN事件,防止接收方直接收到ACTION_MOVE事件无法处理。
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER 标志会将给window发送一个ACTION_DOWN(这里把ACTION_MOVE变为ACTION_DOWN),InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT标志会将给window发送一个ACTION_DOWN(这里把ACTION_MOVE变为ACTION_CANCEL),

处理完case1和case2基本上目标window就找到了,下面做一些额外的处理

1342
1343     if (newHoverWindowHandle != mLastHoverWindowHandle) {1344         // Let the previous window know that the hover sequence is over.
1345         if (mLastHoverWindowHandle != NULL) {1346 #if DEBUG_HOVER
1347             ALOGD("Sending hover exit event to window %s.",
1348                     mLastHoverWindowHandle->getName().string());
1349 #endif// 处理光标事件的window发生变化,要给旧的window一个ACTION_HOVER_EXIT事件
1350             mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
1351                     InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
1352         }
1353
1354         // Let the new window know that the hover sequence is starting.
1355         if (newHoverWindowHandle != NULL) {1356 #if DEBUG_HOVER
1357             ALOGD("Sending hover enter event to window %s.",
1358                     newHoverWindowHandle->getName().string());
1359 #endif// 需要给新的光标处理窗口一个ACTION_HOVER_ENTER事件。
1360             mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
1361                     InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
1362         }
1363     }
1364
1365     // Check permission to inject into all touched foreground windows and ensure there
1366     // is at least one touched foreground window.
1367     {1368         bool haveForegroundWindow = false;
1369         for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {1370             const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
1371             if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {1372                 haveForegroundWindow = true;// 权限检查(处理inject event的权限),没有权限再该事件不能派发。
1373                 if (! checkInjectionPermission(touchedWindow.windowHandle,
1374                         entry->injectionState)) {1375                     injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
1376                     injectionPermission = INJECTION_PERMISSION_DENIED;
1377                     goto Failed;
1378                 }
1379             }
1380         }
1381         if (! haveForegroundWindow) {// 没有前台窗口,也应该决绝派发该事件
1382 #if DEBUG_FOCUS
1383             ALOGW("Dropping event because there is no touched foreground window to receive it.");
1384 #endif
1385             injectionResult = INPUT_EVENT_INJECTION_FAILED;
1386             goto Failed;
1387         }
1388
1389         // Permission granted to injection into all touched foreground windows.
1390         injectionPermission = INJECTION_PERMISSION_GRANTED;
1391     }
1392
1393     // Check whether windows listening for outside touches are owned by the same UID. If it is
1394     // set the policy flag that we will not reveal coordinate information to this window.
1395     if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {// 如果能处理该input事件的其他窗口与前台窗口不在相同应用进程,则不给它们发送坐标信息,只发送事件。// 设置了FLAG_ZERO_COORDS标志的目标窗口收到的事件坐标都是0,0
1396         sp<InputWindowHandle> foregroundWindowHandle =
1397                 mTempTouchState.getFirstForegroundWindowHandle();
1398         const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
1399         for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {1400             const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
1401             if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {1402                 sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
1403                 if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {1404                     mTempTouchState.addOrUpdateWindow(inputWindowHandle,
1405                             InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
1406                 }
1407             }
1408         }
1409     }
1410
1411     // Ensure all touched foreground windows are ready for new input.
1412     for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {1413         const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
1414         if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {// 检查前台窗口是否准备好处理事件,如果没准备好调到Unresponsive标号处执行。
1415             // Check whether the window is ready for more input.
1416             String8 reason = checkWindowReadyForMoreInputLocked(currentTime,
1417                     touchedWindow.windowHandle, entry, "touched");
1418             if (!reason.isEmpty()) {// 处理前台window没有准备好的情况,这里可能上报anr
1419                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
1420                         NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string());
1421                 goto Unresponsive;
1422             }
1423         }
1424     }
1425
1426     // If this is the first pointer going down and the touched window has a wallpaper
1427     // then also add the touched wallpaper windows so they are locked in for the duration
1428     // of the touch gesture.
1429     // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
1430     // engine only supports touch events.  We would need to add a mechanism similar
1431     // to View.onGenericMotionEvent to enable wallpapers to handle these events.
1432     if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {// 如果前台窗口使用了墙纸,那么墙纸顶用需要收到后续ACTION_PARTIALLY_OBSCURED事件,做一些特效处理。
1433         sp<InputWindowHandle> foregroundWindowHandle =
1434                 mTempTouchState.getFirstForegroundWindowHandle();
1435         if (foregroundWindowHandle->getInfo()->hasWallpaper) {1436             for (size_t i = 0; i < mWindowHandles.size(); i++) {1437                 sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
1438                 const InputWindowInfo* info = windowHandle->getInfo();
1439                 if (info->displayId == displayId
1440                         && windowHandle->getInfo()->layoutParamsType
1441                                 == InputWindowInfo::TYPE_WALLPAPER) {1442                     mTempTouchState.addOrUpdateWindow(windowHandle,
1443                             InputTarget::FLAG_WINDOW_IS_OBSCURED
1444                                     | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED
1445                                     | InputTarget::FLAG_DISPATCH_AS_IS,
1446                             BitSet32(0));
1447                 }
1448             }
1449         }
1450     }
1451
1452     // Success!  Output targets.
1453     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
1454 // 将收集到的事件处理窗口添加到 inputTargets的集合中,用于结果输出。
1455     for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {1456         const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
1457         addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
1458                 touchedWindow.pointerIds, inputTargets);
1459     }
1460
1461     // Drop the outside or hover touch windows since we will not care about them
1462     // in the next iteration.// filterNonAsIsTouchWindows函数清除那些不需要再跟踪后续事件的窗口。
1463     mTempTouchState.filterNonAsIsTouchWindows();
1464
1465 Failed:
1466     // Check injection permission once and for all.// 检查注入权限
1467     if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {1468         if (checkInjectionPermission(NULL, entry->injectionState)) {1469             injectionPermission = INJECTION_PERMISSION_GRANTED;
1470         } else {1471             injectionPermission = INJECTION_PERMISSION_DENIED;
1472         }
1473     }
1474
1475     // Update final pieces of touch state if the injector had permission.
1476     if (injectionPermission == INJECTION_PERMISSION_GRANTED) {1477         if (!wrongDevice) {1478             if (switchedDevice) {1479 #if DEBUG_FOCUS
1480                 ALOGW("Conflicting pointer actions: Switched to a different device.");
1481 #endif// 切换设备导致事件冲突
1482                 *outConflictingPointerActions = true;
1483             }
1484
1485             if (isHoverAction) {1486                 // Started hovering, therefore no longer down.
1487                 if (oldState && oldState->down) {// 发生事件冲突,指针已经按下又收到了指针悬停事件
1488 #if DEBUG_FOCUS
1489                     ALOGW("Conflicting pointer actions: Hover received while pointer was down.");
1490 #endif
1491                     *outConflictingPointerActions = true;
1492                 }
1493                 mTempTouchState.reset();
1494                 if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
1495                         || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {1496                     mTempTouchState.deviceId = entry->deviceId;
1497                     mTempTouchState.source = entry->source;
1498                     mTempTouchState.displayId = displayId;// 事件序列开始,更新设备信息
1499                 }
1500             } else if (maskedAction == AMOTION_EVENT_ACTION_UP
1501                     || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {1502                 // All pointers up or canceled.
1503                 mTempTouchState.reset();// AMOTION_EVENT_ACTION_UP 和 AMOTION_EVENT_ACTION_CANCEL表示事件序列已经结束// 清空mTempTouchState
1504             } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {// 点击事件序列开始
1505                 // First pointer went down.
1506                 if (oldState && oldState->down) {1507 #if DEBUG_FOCUS
1508                     ALOGW("Conflicting pointer actions: Down received while already down.");
1509 #endif// 事件冲突
1510                     *outConflictingPointerActions = true;
1511                 }
1512             } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {1513                 // One pointer went up.// 多点触控指针抬起
1514                 if (isSplit) {// 清空处理该事件序列的window
1515                     int32_t pointerIndex = getMotionEventActionPointerIndex(action);
1516                     uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
1517
1518                     for (size_t i = 0; i < mTempTouchState.windows.size(); ) {1519                         TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
1520                         if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {1521                             touchedWindow.pointerIds.clearBit(pointerId);
1522                             if (touchedWindow.pointerIds.isEmpty()) {1523                                 mTempTouchState.windows.removeAt(i);
1524                                 continue;
1525                             }
1526                         }
1527                         i += 1;
1528                     }
1529                 }
1530             }
1531
1532             // Save changes unless the action was scroll in which case the temporary touch
1533             // state was only valid for this one action.
1534             if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {// 更新该屏幕上的TouchState
1535                 if (mTempTouchState.displayId >= 0) {1536                     if (oldStateIndex >= 0) {1537                         mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState);
1538                     } else {1539                         mTouchStatesByDisplay.add(displayId, mTempTouchState);
1540                     }
1541                 } else if (oldStateIndex >= 0) {1542                     mTouchStatesByDisplay.removeItemsAt(oldStateIndex);
1543                 }
1544             }
1545
1546             // Update hover state.
1547             mLastHoverWindowHandle = newHoverWindowHandle;
1548         }
1549     } else {1550 #if DEBUG_FOCUS
1551         ALOGW("Not updating touch focus because injection was denied.");
1552 #endif
1553     }
1554
1555 Unresponsive:
1556     // Reset temporary touch state to ensure we release unnecessary references to input channels.// TouchState已经更新到mTouchStatesByDisplay中,这里恢复mTempTouchState
1557     mTempTouchState.reset();
1558
1559     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);// 更新统计数据
1560     updateDispatchStatisticsLocked(currentTime, entry,
1561             injectionResult, timeSpentWaitingForApplication);
1562 #if DEBUG_FOCUS
1563     ALOGW("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
1564             "timeSpentWaitingForApplication=%0.1fms",
1565             injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
1566 #endif// 返回最终结果。
1567     return injectionResult;
1568 }

前边case1和case2已经将可以处理相关事件的window都添加到了mTempTouchState中,后续再做一些通用处理。1343-1363行代码如果hover事件处理窗口变化,需要发送给旧的处理hover事件window一个ACTION_HOVER_EXIT事件,这是通过设置InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT 标志来完成的。新的处理hover事件的window需要接收一个ACTION_HOVER_ENTER事件,这是通过设置一个InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER标志来完成的。
1369-1380行代码检查注入事件能否发送给目标应用,主要通过PhoneWindowManager来进行权限检查。
1395-1409行代码如果能接收input的window和前台window不在相同的应用进程中,则后续发给给它的事件将不包含真实坐标,通过设置InputTarget::FLAG_ZERO_COORDS标志来实现的。
1412-1424行代码检查前台窗口有没有准备好处理input事件,如果没有准备好就会调用handleTargetsNotReadyLocked函数来处理,注意应用anr事件也是在这里上报的。
1432-1450 行代码如果前台窗口需要显示墙纸,那么需要发送给墙纸窗口ACTION_PARTIALLY_OBSCURED事件,来实现一些特效。所以给墙纸窗口添加一个InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED标志。
1455-1459行代码将收集到的接收input事件的窗口添加到输出参数inputTargets中,用于给上层函数进行事件派发。
1643行代码 filterNonAsIsTouchWindows函数清除那些不需要再跟踪后续事件的窗口。

void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {for (size_t i = 0 ; i < windows.size(); ) {TouchedWindow& window = windows.editItemAt(i);if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS| InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;i += 1;} else {windows.removeAt(i);}}
}

filterNonAsIsTouchWindows函数如果一个处理事件没有FLAG_DISPATCH_AS_IS标志或者FLAG_DISPATCH_AS_SLIPPERY_ENTER标志,那么该window不需要处理后续事件,就直接删除。后续MOVE, UP, CANCEL等事件将不再发送给该窗口处理。另外除了FLAG_DISPATCH_AS_IS标志会保留外其他标志也会被清除。也就是说后续的ACTION_PARTIALLY_OBSCURED,ACTION_OBSCURED事件也无法收到(只能收到down的事件)。
1500-1503行代码AMOTION_EVENT_ACTION_UP 和AMOTION_EVENT_ACTION_CANCEL事件,表示一个事件序列结束,所以清除到mTempTouchState中保存的事件序列信息。
1512-1530行代码AMOTION_EVENT_ACTION_POINTER_UP事件,如果拆分touch事件的情况,代表处理该事件序列也已经结束,清除对应处理该事件的window。
1534-1544行代码更新TouchStat到mTouchStatesByDisplay。
1557行 TouchState已经更新到mTouchStatesByDisplay中,这里重置mTempTouchState
1559-1565行做一些统计工作,最终返回injectionResult,表示该如何处理该事件。

收集到处理事件的window后,最终事件通过dispatchEventLocked(currentTime, entry, inputTargets)函数派发, dispatchEventLocked函数又会调用prepareDispatchCycleLocked函数, prepareDispatchCycleLocked函数调用enqueueDispatchEntriesLocked函数来将事件转化为发送给应用窗口的对应事件。

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {bool wasEmpty = connection->outboundQueue.isEmpty();// Enqueue dispatch entries for the requested modes.enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_OUTSIDE);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_IS);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);// If the outbound queue was previously empty, start the dispatch cycle going.if (wasEmpty && !connection->outboundQueue.isEmpty()) {startDispatchCycleLocked(currentTime, connection);}
}

对于不同inputTargetFlage会产生不同的事件派发给window。有
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT,InputTarget::FLAG_DISPATCH_AS_OUTSIDE,InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,InputTarget::FLAG_DISPATCH_AS_IS,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER前边我们已经介绍过了。

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,int32_t dispatchMode) {int32_t inputTargetFlags = inputTarget->flags;if (!(inputTargetFlags & dispatchMode)) { // 如果targetFlag不包含dispatchMode则不会产生相应的事件,直接返回。return;}inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;// This is a new event.// Enqueue a new dispatch entry onto the outbound queue for this connection.DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments refinputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,inputTarget->scaleFactor);// Apply target flags and update the connection's input state.switch (eventEntry->type) {case EventEntry::TYPE_KEY: {KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);dispatchEntry->resolvedAction = keyEntry->action;dispatchEntry->resolvedFlags = keyEntry->flags;if (!connection->inputState.trackKey(keyEntry,dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",connection->getInputChannelName());
#endifdelete dispatchEntry;return; // skip the inconsistent event}break;}case EventEntry::TYPE_MOTION: {MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;} else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;} else {dispatchEntry->resolvedAction = motionEntry->action;}if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE&& !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",connection->getInputChannelName());
#endifdispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;}dispatchEntry->resolvedFlags = motionEntry->flags;if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;}if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;}if (!connection->inputState.trackMotion(motionEntry,dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",connection->getInputChannelName());
#endifdelete dispatchEntry;return; // skip the inconsistent event}break;}}// Remember that we are waiting for this dispatch to complete.if (dispatchEntry->hasForegroundTarget()) {incrementPendingForegroundDispatchesLocked(eventEntry);}// Enqueue the dispatch entry.connection->outboundQueue.enqueueAtTail(dispatchEntry);traceOutboundQueueLengthLocked(connection);
}

enqueueDispatchEntryLocked函数根据目标窗口的targetFlag和dispatchMode来设置事件的dispatchEntry->resolvedAction,也就是要发送给该窗口的事件类型。

Android InputDispatch事件派发->选择目标窗口相关推荐

  1. Android触摸事件派发(一) ViewGroup的dispatchTouchEvent()

    ViewGroup的派发事件代码主要由dispatchTouchEvent(MotionEvent ev)方法实现,如下 @Overridepublic boolean dispatchTouchEv ...

  2. android 事件派发流程详解

    Android 5.0(Lollipop)事件输入系统(Input System) 2014-12-15      23 个评论   来源:世事难料,保持低调   收藏   我要投稿 其实Androi ...

  3. 利用勾子监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统.每当特定     的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得     到控制权.这时钩子函数即可以加工处理 ...

  4. Android系统(120)-android的事件分发机制

    android的事件分发机制 android的事件分发机制 比如说,现在你所在的公司中有一项任务被派发下来了,项目经理把项目交给你的老大,你的老大老大手下有很多人,看了看觉得你做很合适,把这个任务交给 ...

  5. Android 输入事件一撸到底之View接盘侠(3)

    前言 系列文章 1.Android 输入事件一撸到底之源头活水(1) 2.Android 输入事件一撸到底之DecorView拦路虎(2) 3.Android 输入事件一撸到底之View接盘侠(3 前 ...

  6. 为了讲清楚Android触摸事件,我“拆了部手机”

    Android 是一个有用户界面(GUI)的操作系统,在它诞生之初,就是为带有触摸屏的手持设备准备的.作为提供给用户最重要的交互方式之一,了解触摸系统是怎么工作的,对于实际的项目开发有着非常大的帮助. ...

  7. Android的事件分发

    1. Touch事件和绘制事件的异同之处 Touch事件和绘制事件很类似,都是由ViewRoot派发下来的,但是不同之处在绘制事件是由应用中的某个View发起请求,一层一层上传到ViewRoot,再有 ...

  8. Android 系统(218)---Android的事件分发机制以及滑动冲突的解决

    Android的事件分发机制以及滑动冲突的解决 声明:  本文主要涉及VIew的事件分发与滑动冲突的解决,关于View的事件分发流程的部分内容参考自:  Android事件分发机制详解:史上最全面.最 ...

  9. 一文读懂Android View事件分发机制

    Android View 虽然不是四大组件,但其并不比四大组件的地位低.而View的核心知识点事件分发机制则是不少刚入门同学的拦路虎.ScrollView嵌套RecyclerView(或者ListVi ...

最新文章

  1. 《The Art of Readable Code》 读书笔记 01
  2. 对话高博(二)| 换工作这件事
  3. 如何在网站建设时正确设置符合SEO优化的元素?
  4. 100小时学会sap-财务篇fico总结介绍篇
  5. ai去除水印_ai全自动视频剪辑软件,每天批量制作800条原创视频!
  6. 学习Java之前先学C语言
  7. JUC:ConcurrentSkipListMap/ConcurrentSkipListSet(并发容器)
  8. Atitit Kafka 使用总结 内容 Kafka2.0 50M1 启动 要启动zookeeper 先,比ativemp麻烦很多啊1 Kafka生产者 1 Kafka消费者2 2
  9. 编译安装nginx并修改版本头信息—参考实例
  10. 哈理工OJ 1151 追求(斐波那契变形【思维题目】)
  11. 斗鱼弹幕服务器未响应,斗鱼看不到弹幕的解决方法步骤
  12. 安徽大学线性代数习题册(第三章详细解答)
  13. 新手如何Reverces(3自动化逆向篇)
  14. 一根均线选股法_一条均线走天下,经典实用的均线选股战法,学会让你少走弯路!...
  15. 北京著名“十大特色美食街”
  16. sqlDBX 链接 mysql 提示ODBC驱动不正确
  17. [ CTF ]【天格】战队WriteUp-第六届”蓝帽杯“全国大学生网络安全技能大赛(半决赛)
  18. python 使用 io.BytesIO 内存文件加速图片生成服务
  19. 【实用工具系列之爬虫】python实现爬取代理IP(防 ‘反爬虫’)
  20. Stanford Large-Scale 3D Indoor Spaces Dataset (S3DIS)

热门文章

  1. k8s使用的iptables,具体原理是什么?一学就会
  2. html盒子里的内容溢出,[经验] HTML页面中子盒子溢出了怎么办
  3. 物联网+Android(SeekBar)、RGB灯控制
  4. opencv 手选roi区域_【OpenCV】选择ROI区域
  5. 编码器基础知识大扫盲
  6. 线性规划——对偶问题、强弱对偶定理、KKT条件
  7. PMP第三章:项目经理的角色
  8. 大数据的反思:不可不知的几个小故事
  9. python pdf与图片互转
  10. 从现在看未来,在未来看现在