Android InputDispatch事件派发->选择目标窗口

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

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

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

Input Dispatcher State:
  DispatchEnabled: 1
  DispatchFrozen: 0
  FocusedApplication: name='AppWindowToken{9ab95fe token=Token{867fdb9 ActivityRecord{c189380 u0 com.android.contacts/.activities.CompactContactEditorActivity t6}}}', dispatchingTimeout=5000.000ms
  FocusedWindow: 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.000ms
    1: 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.000ms
    2: 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.000ms
    3: 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.000ms
    4: 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.000ms
    5: 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.000ms
    6: 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.000ms
    7: 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;  // flags
    int32_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-order
    int32_t ownerPid;  // 所属应用进程的pid
    int32_t ownerUid; // 所属应用进程的uid
    int32_t inputFeatures; // 支持的feature
    int32_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 rejected
        uint32_t source;  // source of the device that is current down, others are rejected
        int32_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 ref
            inputTargetFlags, 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_CYCLE
            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
                    connection->getInputChannelName());
#endif
            delete 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_CYCLE
        ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
                connection->getInputChannelName());
#endif
            dispatchEntry->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_CYCLE
            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
                    connection->getInputChannelName());
#endif
            delete 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,也就是要发送给该窗口的事件类型。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值