Android输入输出系统之TouchEvent流程
一个是InputReader,一个是InputDispatcher。方法是dispatchTouch。
入口点是InputReader 的loopOnce方法.
InputReader里面有个线程叫做InputReaderThread,threadLoop
[code="java"]InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
- void InputDispatcher::dispatchOnce() {
- nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
- nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
- nsecs_t nextWakeupTime = LONG_LONG_MAX;
- { // acquire lock
- AutoMutex _l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
- if (runCommandsLockedInterruptible()) {
- nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
- }
- } // release lock
- // Wait for callback or timeout or wake. (make sure we round up, not down)
- nsecs_t currentTime = now();
- int32_t timeoutMillis;
- if (nextWakeupTime > currentTime) {
- uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
- timeout = (timeout + 999999LL) / 1000000LL;
- timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
- } else {
- timeoutMillis = 0;
- }
- mLooper->pollOnce(timeoutMillis);
- }
- case EventEntry::TYPE_MOTION: {
- MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
- if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
- dropReason = DROP_REASON_APP_SWITCH;
- }
- done = dispatchMotionLocked(currentTime, typedEntry,
- &dropReason, nextWakeupTime);
- break;
- bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
- // Preprocessing.
- if (! entry->dispatchInProgress) {
- entry->dispatchInProgress = true;
- resetTargetsLocked();
- logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
- }
- // Clean up if dropping the event.
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
- resetTargetsLocked();
- setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
- ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
- return true;
- }
- bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
- // Identify targets.
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult;
- if (isPointerEvent) {
- // Pointer event. (eg. touchscreen)
- injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- } else {
- // Non touch event. (eg. trackball)
- injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- }
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- return true;
- }
- addMonitoringTargetsLocked();
- commitTargetsLocked();
- }
- // Dispatch the motion.
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
- return true;
- }
- startDispatchCycleLocked 中的方法
- status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
- motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
- xOffset, yOffset,
- motionEntry->xPrecision, motionEntry->yPrecision,
- motionEntry->downTime, firstMotionSample->eventTime,
- motionEntry->pointerCount, motionEntry->pointerIds,
- firstMotionSample->pointerCoords);
- ViewRoot有个InputHandler
- private final InputHandler mInputHandler = new InputHandler() {
- public void handleKey(KeyEvent event, Runnable finishedCallback) {
- startInputEvent(finishedCallback);
- dispatchKey(event, true);
- }
- public void handleMotion(MotionEvent event, Runnable finishedCallback) {
- startInputEvent(finishedCallback);
- dispatchMotion(event, true);
- }
- };
InputHandler注册给了系统
- InputQueue.registerInputChannel(mInputChannel, mInputHandler,
- Looper.myQueue());
- dispatchMotion(event, true);方法如下
- rivate void dispatchMotion(MotionEvent event, boolean sendDone) {
- int source = event.getSource();
- if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- dispatchPointer(event, sendDone);
- } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
- dispatchTrackball(event, sendDone);
- } else {
- // TODO
- Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
- if (sendDone) {
- finishInputEvent();
- }
- }
- }
调用了dispatchPointer
ViewRoot本身就是Handler直接sendMessageAtTime
然后就进入了View的焦点系统。
下面就说一下Activity的焦点是怎么回事。
- InputDisapatcher.cpp中调用了如下方法
- dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
- true /*resumeWithAppendedMotionSample*/);
然后
- dispatchEventToCurrentInputTargetsLocked
调用了如下方法
- int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, nsecs_t* nextWakeupTime) {
- mCurrentInputTargets.clear();
- int32_t injectionResult;
- // If there is no currently focused window and no focused application
- // then drop the event.
- if (! mFocusedWindow) {
- if (mFocusedApplication) {
- #if DEBUG_FOCUS
- LOGD("Waiting because there is no focused window but there is a "
- "focused application that may eventually add a window: %s.",
- getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
- #endif
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
- goto Unresponsive;
- }
- LOGI("Dropping event because there is no focused window or focused application.");
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
- // Check permissions.
- if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
- injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- goto Failed;
- }
- // If the currently focused window is paused then keep waiting.
- if (mFocusedWindow->paused) {
- #if DEBUG_FOCUS
- LOGD("Waiting because focused window is paused.");
- #endif
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
- goto Unresponsive;
- }
- // If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
- #if DEBUG_FOCUS
- LOGD("Waiting because focused window still processing previous input.");
- #endif
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
- goto Unresponsive;
- }
- // Success! Output targets.
- injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
- // Done.
- Failed:
- Unresponsive:
- nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatisticsLocked(currentTime, entry,
- injectionResult, timeSpentWaitingForApplication);
- #if DEBUG_FOCUS
- LOGD("findFocusedWindow finished: injectionResult=%d, "
- "timeSpendWaitingForApplication=%0.1fms",
- injectionResult, timeSpentWaitingForApplication / 1000000.0);
- #endif
- return injectionResult;
- }
move事件的处理和Down事件的处理很不相同。
新建立的Window在处理焦点的时候,按下事件没有起来之前,保持了原来的焦点窗口。除非ACTION_UP事件收到以后
- /* Updates the cached window information provided to the input dispatcher. */
- public void updateInputWindowsLw() {
- // Populate the input window list with information about all of the windows that
- // could potentially receive input.
- // As an optimization, we could try to prune the list of windows but this turns
- // out to be difficult because only the native code knows for sure which window
- // currently has touch focus.
- final ArrayList<WindowState> windows = mWindows;
- final int N = windows.size();
- for (int i = N - 1; i >= 0; i--) {
- final WindowState child = windows.get(i);
- if (child.mInputChannel == null || child.mRemoved) {
- // Skip this window because it cannot possibly receive input.
- continue;
- }
- final int flags = child.mAttrs.flags;
- final int type = child.mAttrs.type;
- final boolean hasFocus = (child == mInputFocus);
- final boolean isVisible = child.isVisibleLw();
- final boolean hasWallpaper = (child == mWallpaperTarget)
- && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
- // Add a window to our list of input windows.
- final InputWindow inputWindow = mTempInputWindows.add();
- inputWindow.inputChannel = child.mInputChannel;
- inputWindow.name = child.toString();
- inputWindow.layoutParamsFlags = flags;
- inputWindow.layoutParamsType = type;
- inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
- inputWindow.visible = isVisible;
- inputWindow.canReceiveKeys = child.canReceiveKeys();
- inputWindow.hasFocus = hasFocus;
- inputWindow.hasWallpaper = hasWallpaper;
- inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
- inputWindow.layer = child.mLayer;
- inputWindow.ownerPid = child.mSession.mPid;
- inputWindow.ownerUid = child.mSession.mUid;
- final Rect frame = child.mFrame;
- inputWindow.frameLeft = frame.left;
- inputWindow.frameTop = frame.top;
- inputWindow.frameRight = frame.right;
- inputWindow.frameBottom = frame.bottom;
- final Rect visibleFrame = child.mVisibleFrame;
- inputWindow.visibleFrameLeft = visibleFrame.left;
- inputWindow.visibleFrameTop = visibleFrame.top;
- inputWindow.visibleFrameRight = visibleFrame.right;
- inputWindow.visibleFrameBottom = visibleFrame.bottom;
- switch (child.mTouchableInsets) {
- default:
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
- inputWindow.touchableAreaLeft = frame.left;
- inputWindow.touchableAreaTop = frame.top;
- inputWindow.touchableAreaRight = frame.right;
- inputWindow.touchableAreaBottom = frame.bottom;
- break;
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
- Rect inset = child.mGivenContentInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
- Rect inset = child.mGivenVisibleInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
- }
- }
- // Send windows to native code.
- mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
- // Clear the list in preparation for the next round.
- // Also avoids keeping InputChannel objects referenced unnecessarily.
- mTempInputWindows.clear();
- }
真正的Input的控制是通过以下方式
/**
* Z-ordered (bottom-most first) list of all Window objects.
*/
final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
- /**
- * Z-ordered (bottom-most first) list of all Window objects.
- */
- final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
另外的touch的target并不是通过input focus 获得的。而是通过visible来获得
- 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 < numWindows; 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 < mTempTouchState.windows.size(); 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 < mTempTouchState.windows.size(); 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 < mWindows.size(); 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 < mTempTouchState.windows.size(); 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 < mTempTouchState.windows.size(); ) {
- 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;
- }
最关键的几行代码,说明了Windows是如何找到触屏的输入焦点的:
- 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));
- }
- }
- // Focus tracking for touch.
- struct TouchedWindow {
- const InputWindow* window;
- int32_t targetFlags;
- BitSet32 pointerIds;
- sp<InputChannel> channel;
- };
- struct TouchState {
- bool down;
- bool split;
- Vector<TouchedWindow> windows;
- TouchState();
- ~TouchState();
- void reset();
- void copyFrom(const TouchState& other);
- void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
- void removeOutsideTouchWindows();
- const InputWindow* getFirstForegroundWindow();
- };
- 另外如何定义按键和其他触屏焦点的:
- /* Updates the cached window information provided to the input dispatcher. */
- public void updateInputWindowsLw() {
- // Populate the input window list with information about all of the windows that
- // could potentially receive input.
- // As an optimization, we could try to prune the list of windows but this turns
- // out to be difficult because only the native code knows for sure which window
- // currently has touch focus.
- final ArrayList<WindowState> windows = mWindows;
- final int N = windows.size();
- for (int i = N - 1; i >= 0; i--) {
- final WindowState child = windows.get(i);
- if (child.mInputChannel == null || child.mRemoved) {
- // Skip this window because it cannot possibly receive input.
- continue;
- }
- final int flags = child.mAttrs.flags;
- final int type = child.mAttrs.type;
- <span style="color: #ff6600;"> final boolean hasFocus = (child == mInputFocus);</span>
- //本行代码确定,一次性的focusWindow只有一个。
- final boolean isVisible = child.isVisibleLw();
- final boolean hasWallpaper = (child == mWallpaperTarget)
- && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
Android输入输出系统之TouchEvent流程的更多相关文章
- 深入理解 Android 之 View 的绘制流程
概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...
- Android的系统体系结构
目录: Android的系统体系结构 Android的四种常用组件 Activity的启动流程 Android的系统体系结构 在入门了一个简单的Android的Hello World以后,我们首先来看 ...
- android Gui系统之SurfaceFlinger(3)---SurfaceFlinger
7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...
- Android GUI系统
图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...
- Android系统架构-----Android的系统体系架构
一.Android的系统体系结构 在入门了一个简单的Android的Hello World以后,我们首先来看一下我们Android的整体系统架构图: 这个就是我们Android的整体系统架构图了,我们 ...
- Android调用系统相册和拍照的Demo
最近我在群里看到有好几个人在交流说现在网上的一些Android调用系统相册和拍照的demo都有bug,有问题,没有一个完整的.确实是,我记得一个月前,我一同学也遇到了这样的问题,在低版本的系统中没问题 ...
- 图解Android - Android GUI 系统 (1) - 概论
Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- 图解Android - Android GUI 系统 (5) - Android的Event Input System
Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...
随机推荐
- [转]Java Web乱码过滤器
本文转自http://blog.csdn.net/l271640625/article/details/6388690 大家都知道,在jsp里乱码是最让人讨厌的东西,有些乱码出来的莫名其妙,给开发带来 ...
- 【quick-cocos2d-x】Lua 面向对象(OOP)编程与元表元方法
版权声明:本文为博主原创文章,转载请注明出处. 面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物. 早期的计算机编程是基于面向过程的方法,通过设计一个算法就可以解决当时 ...
- python字典概述
字典 1. 概述 字典是一个无序的数据集合,序列类型用有序的数字键做索引将数据以数组的形式存储. 在字典中能获得的有序集合只能是键的集合或者是值得集合,方法keys()或者value()返回一个 ...
- 55个高质量的Magento主题,助你构建电子商务站点
Magento是一个功能丰富的开源电子商务平台(译者注:基于PHP的Zend Framework开发),在网店的外观.商品管理以及其它功能上,它给商家提供了前所未有的灵活和易用性.通过挑选一个合适的M ...
- 20 个超酷的 HTML5/CSS3 应用及源码
[导读] 1.HTML5视频破碎重组特效,强大视觉冲击HTML5视频播放器很多,但是HTML5视频特效还是很少见的,这款HTML5视频破碎重组特效非常刺激,给人强大的视觉冲击.点击视频任意地方,HTM ...
- poj 3006 Dirichlet's Theorem on Arithmetic Progressions
题目大意:a和d是两个互质的数,则序列a,a+d,a+2d,a+3d,a+4d ...... a+nd 中有无穷多个素数,给出a和d,找出序列中的第n个素数 #include <cstdio&g ...
- java Study 基础 1
1.myEclipse 生成get.set,source>Generate getter and setter 2.Web servlet.HttpServlet.HttpServletRequ ...
- pd虚拟机死机怎么解决
最近在mac上使用pd虚拟机装win使用,今天发现pd中的win7虚拟机死机了,无论怎么点都没用,通过点击操作-关闭也不行,重启电脑也不行,后来找到一种办法可以重启虚拟机. 1.先通过菜单中止虚拟机, ...
- 使用Windows Azure创建和发布ASP.NET应用程序
Windows Azure为我们提供了一个功能强大的PaaS平台,使得我们无须部署和维护基础架构就可以根据需求发布开发的应用程序,并且支持多种语言及平台,如:ASP.NET, PHP, Python, ...
- 恢复HDFS误删数据
[恢复HDFS误删数据] HDFS会为每一个用户创建一个回收站目录:/user/用户名/.Trash/,每一个被用户通过Shell删除的文件/目录,在系统回收站中都一个周期,也就是当系统回收站中的文件 ...