当用户触屏后,InputReader 从驱动读取一个输入事件加入到队列,InputDispatcher 从队列中读取一个输入事件准备分发。
如果该输入事件是一个触摸事件,则先查找最上层可接受该 Touch 的窗口。然后通过 Socket 发送给对应的 InputConsumer。
InputConsumer 会发送给相应的 InputEventReceiver 实现类。该实现类中分发给每一个 InputStage 责任链,InputStage 实现类会最终处理该输入事件。
参考「InputChannel and InputDispatcher in Android」。
Gityuan 的「Input 系统—事件处理全过程」有个整体框架图如下:
一个触摸事件该不该发给一个窗口,取决于该窗口的可触摸区域是否包含该触摸的坐标,且没有被别的窗口的可触摸区域盖住。
该逻辑实现在 findTouchedWindowAtLocked()
函数中,它会遍历所有的 InputWindowHandle,然后调用 windowInfo->touchableRegionContainsPoint(x, y)
检查可触摸区域是否包含该触摸点坐标。如果满足则返回。
// frameworks/native/services/inputflinger/InputDispatcher.cpp
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {
// Traverse windows from front to back to find touched window.
const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
int32_t flags = windowInfo->layoutParamsFlags;
if (windowInfo->visible) {
if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
...
// Found window.
return windowHandle;
}}
...
}}}
return nullptr;
}
这里为什么会叫可触摸区域(Touchable Region),而不是窗口大小,是因为可触摸区域可以和显示窗口不一样,甚至可以由多个矩形组成(一个显示窗口只能是一个矩形)。
InputWindowHandle 持有 InputWindowInfo 对象,InputWindowInfo 有成员 touchableRegion
。它是 Region 类对象,注意是在 framework/native/include/ui/Region.h 中声明的 Region 类。
// frameworks/native/include/input/InputWindow.h
struct InputWindowInfo {
...
Region touchableRegion;
void addTouchableRegion(const Rect& regin);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
...
}
class InputWindowHandle : public RefBase {
public:
inline const InputWindowInfo* getInfo() const {
return &mInfo;
}
...
protected:
InputWindowInfo mInfo;
};
// frameworks/native/include/ui/Region.h
class Region : public LightFlattenable<Region>
{
public:
inline bool contains(int x, int y) const;
...
// STL-like iterators
typedef Rect const* const_iterator;
const_iterator begin() const;
const_iterator end() const;
...
// mStorage is a (manually) sorted array of Rects describing the region
// with an extra Rect as the last element which is set to the
// bounds of the region. However, if the region is
// a simple Rect then mStorage contains only that rect.
Vector<Rect> mStorage;
};
Region 类的成员 mStorage
是一个 Vector<Rect>
对象,从这里也可以知道可触摸区域由多个矩形组成的。
InputWindowInfo 结构体中的 touchableRegion
其实是从 Java 层过来的,是 Java InputWindowHandle 类的 touchableRegion
成员。
// frameworks/base/core/java/android/view/InputWindowHandle.java
public final class InputWindowHandle {
...
public final Region touchableRegion = new Region();
...
}
这个 touchableRegion
是在 UpdateInputForAllWindowsConsumer 的 updateInputWindows()
方法中遍历 DisplayContent 的所有 WindowState 时计算的。