记不住密码怎么办?
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 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);
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 ArrayList mWindows = 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;
sp channel;
};
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