android touch处理流程,Android输入输出系统之TouchEvent流程

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,

const MotionEntry* entry, nsecs_t* nextWakeupTime) {

enum InjectionPermission {

INJECTION_PERMISSION_UNKNOWN,

INJECTION_PERMISSION_GRANTED,

INJECTION_PERMISSION_DENIED

};

mCurrentInputTargets.clear();

nsecs_t startTime = now();

// For security reasons, we defer updating the touch state until we are sure that

// event injection will be allowed.

//

// FIXME In the original code, screenWasOff could never be set to true.

//       The reason is that the POLICY_FLAG_WOKE_HERE

//       and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw

//       EV_KEY, EV_REL and EV_ABS events.  As it happens, the touch event was

//       actually enqueued using the policyFlags that appeared in the final EV_SYN

//       events upon which no preprocessing took place.  So policyFlags was always 0.

//       In the new native input dispatcher we're a bit more careful about event

//       preprocessing so the touches we receive can actually have non-zero policyFlags.

//       Unfortunately we obtain undesirable behavior.

//

//       Here's what happens:

//

//       When the device dims in anticipation of going to sleep, touches

//       in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause

//       the device to brighten and reset the user activity timer.

//       Touches on other windows (such as the launcher window)

//       are dropped.  Then after a moment, the device goes to sleep.  Oops.

//

//       Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE

//       instead of POLICY_FLAG_WOKE_HERE...

//

bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;

int32_t action = entry->action;

int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;

// Update the touch state as needed based on the properties of the touch event.

int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;

InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;

if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {

mTempTouchState.reset();

mTempTouchState.down = true;

} else {

mTempTouchState.copyFrom(mTouchState);

}

bool isSplit = mTempTouchState.split && mTempTouchState.down;

if (maskedAction == AMOTION_EVENT_ACTION_DOWN

|| (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {

/* Case 1: New splittable pointer going down. */

int32_t pointerIndex = getMotionEventActionPointerIndex(action);

int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex].x);

int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].y);

const InputWindow* newTouchedWindow = NULL;

const InputWindow* topErrorWindow = NULL;

// Traverse windows from front to back to find touched window and outside targets.

size_t numWindows = mWindows.size();

for (size_t i = 0; i 

const InputWindow* window = & mWindows.editItemAt(i);

int32_t flags = window->layoutParamsFlags;

if (flags & InputWindow::FLAG_SYSTEM_ERROR) {

if (! topErrorWindow) {

topErrorWindow = window;

}

}

if (window->visible) {

if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {

bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE

| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;

if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {

if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {

newTouchedWindow = window;

}

break; // found touched window, exit window loop

}

}

if (maskedAction == AMOTION_EVENT_ACTION_DOWN

&& (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {

int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;

if (isWindowObscuredAtPointLocked(window, x, y)) {

outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;

}

mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));

}

}

}

// If there is an error window but it is not taking focus (typically because

// it is invisible) then wait for it.  Any other focused window may in

// fact be in ANR state.

if (topErrorWindow && newTouchedWindow != topErrorWindow) {

#if DEBUG_FOCUS

LOGD("Waiting because system error window is pending.");

#endif

injectionResult = handleTargetsNotReadyLocked(currentTime, entry,

NULL, NULL, nextWakeupTime);

injectionPermission = INJECTION_PERMISSION_UNKNOWN;

goto Unresponsive;

}

// Figure out whether splitting will be allowed for this window.

if (newTouchedWindow

&& (newTouchedWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH)) {

// New window supports splitting.

isSplit = true;

} else if (isSplit) {

// New window does not support splitting but we have already split events.

// Assign the pointer to the first foreground window we find.

// (May be NULL which is why we put this code block before the next check.)

newTouchedWindow = mTempTouchState.getFirstForegroundWindow();

}

// If we did not find a touched window then fail.

if (! newTouchedWindow) {

if (mFocusedApplication) {

#if DEBUG_FOCUS

LOGD("Waiting because there is no touched window but there is a "

"focused application that may eventually add a new window: %s.",

getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());

#endif

injectionResult = handleTargetsNotReadyLocked(currentTime, entry,

mFocusedApplication, NULL, nextWakeupTime);

goto Unresponsive;

}

LOGI("Dropping event because there is no touched window or focused application.");

injectionResult = INPUT_EVENT_INJECTION_FAILED;

goto Failed;

}

// Set target flags.

int32_t targetFlags = InputTarget::FLAG_FOREGROUND;

if (isSplit) {

targetFlags |= InputTarget::FLAG_SPLIT;

}

if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {

targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;

}

// Update the temporary touch state.

BitSet32 pointerIds;

if (isSplit) {

uint32_t pointerId = entry->pointerIds[pointerIndex];

pointerIds.markBit(pointerId);

}

mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);

} else {

/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */

// If the pointer is not currently down, then ignore the event.

if (! mTempTouchState.down) {

LOGI("Dropping event because the pointer is not down.");

injectionResult = INPUT_EVENT_INJECTION_FAILED;

goto Failed;

}

}

// Check permission to inject into all touched foreground windows and ensure there

// is at least one touched foreground window.

{

bool haveForegroundWindow = false;

for (size_t i = 0; i 

const TouchedWindow& touchedWindow = mTempTouchState.windows[i];

if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {

haveForegroundWindow = true;

if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {

injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;

injectionPermission = INJECTION_PERMISSION_DENIED;

goto Failed;

}

}

}

if (! haveForegroundWindow) {

#if DEBUG_INPUT_DISPATCHER_POLICY

LOGD("Dropping event because there is no touched foreground window to receive it.");

#endif

injectionResult = INPUT_EVENT_INJECTION_FAILED;

goto Failed;

}

// Permission granted to injection into all touched foreground windows.

injectionPermission = INJECTION_PERMISSION_GRANTED;

}

// Ensure all touched foreground windows are ready for new input.

for (size_t i = 0; i 

const TouchedWindow& touchedWindow = mTempTouchState.windows[i];

if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {

// If the touched window is paused then keep waiting.

if (touchedWindow.window->paused) {

#if DEBUG_INPUT_DISPATCHER_POLICY

LOGD("Waiting because touched window is paused.");

#endif

injectionResult = handleTargetsNotReadyLocked(currentTime, entry,

NULL, touchedWindow.window, nextWakeupTime);

goto Unresponsive;

}

// If the touched window is still working on previous events then keep waiting.

if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {

#if DEBUG_FOCUS

LOGD("Waiting because touched window still processing previous input.");

#endif

injectionResult = handleTargetsNotReadyLocked(currentTime, entry,

NULL, touchedWindow.window, nextWakeupTime);

goto Unresponsive;

}

}

}

// If this is the first pointer going down and the touched window has a wallpaper

// then also add the touched wallpaper windows so they are locked in for the duration

// of the touch gesture.

if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {

const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();

if (foregroundWindow->hasWallpaper) {

for (size_t i = 0; i 

const InputWindow* window = & mWindows[i];

if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {

mTempTouchState.addOrUpdateWindow(window,

InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));

}

}

}

}

// Success!  Output targets.

injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;

for (size_t i = 0; i 

const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);

addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,

touchedWindow.pointerIds);

}

// Drop the outside touch window since we will not care about them in the next iteration.

mTempTouchState.removeOutsideTouchWindows();

Failed:

// Check injection permission once and for all.

if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {

if (checkInjectionPermission(NULL, entry->injectionState)) {

injectionPermission = INJECTION_PERMISSION_GRANTED;

} else {

injectionPermission = INJECTION_PERMISSION_DENIED;

}

}

// Update final pieces of touch state if the injector had permission.

if (injectionPermission == INJECTION_PERMISSION_GRANTED) {

if (maskedAction == AMOTION_EVENT_ACTION_UP

|| maskedAction == AMOTION_EVENT_ACTION_CANCEL) {

// All pointers up or canceled.

mTempTouchState.reset();

} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {

// First pointer went down.

if (mTouchState.down) {

#if DEBUG_FOCUS

LOGD("Pointer down received while already down.");

#endif

}

} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {

// One pointer went up.

if (isSplit) {

int32_t pointerIndex = getMotionEventActionPointerIndex(action);

uint32_t pointerId = entry->pointerIds[pointerIndex];

for (size_t i = 0; i 

TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);

if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {

touchedWindow.pointerIds.clearBit(pointerId);

if (touchedWindow.pointerIds.isEmpty()) {

mTempTouchState.windows.removeAt(i);

continue;

}

}

i += 1;

}

}

}

// Save changes to touch state.

mTouchState.copyFrom(mTempTouchState);

} else {

#if DEBUG_FOCUS

LOGD("Not updating touch focus because injection was denied.");

#endif

}

Unresponsive:

// Reset temporary touch state to ensure we release unnecessary references to input channels.

mTempTouchState.reset();

nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);

updateDispatchStatisticsLocked(currentTime, entry,

injectionResult, timeSpentWaitingForApplication);

#if DEBUG_FOCUS

LOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "

"timeSpentWaitingForApplication=%0.1fms",

injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);

#endif

return injectionResult;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值