记不住密码怎么办?
http://a.app.qq.com/o/simple.jsp?pkgname=com.wa505.kf.epassword
一个是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(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);方法如下 private 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 ArrayListwindows = 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
/** * Z-ordered (bottom-most first) list of all Window objects. */ final ArrayListmWindows = new ArrayList ();
另外的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; spchannel; }; struct TouchState { bool down; bool split; Vector 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 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); //本行代码确定,一次性的focusWindow只有一个。 final boolean isVisible = child.isVisibleLw(); final boolean hasWallpaper = (child == mWallpaperTarget) && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
记不住密码怎么办?
http://a.app.qq.com/o/simple.jsp?pkgname=com.wa505.kf.epassword