google推出的carboard、daydream是没有usb接口的,调节全靠手机自身的sensor。而想gear vr这类VR眼镜是有USB接口的,眼镜内部是有sensor用户调节眼镜的,而且有触屏、返回键和音量调节键。是不是很像一个鼠标。

add device 1: /dev/input/event19

name: "XXXX VR, Inc. x HID"

could not get driver version for /dev/input/mouse1, Not a typewriter

shell状态下输入getevent -l,/dev/input/mouse1确实是一个鼠标,证明了我们的猜想。

下面我们从设备输入的源头InputReader.cpp进行分析。

InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

initialize();

}

void InputManager::initialize() {

mReaderThread = new InputReaderThread(mReader);

mDispatcherThread = new InputDispatcherThread(mDispatcher);

}

status_t InputManager::start() {

status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);

if (result) {

ALOGE("Could not start InputDispatcher thread due to error %d.", result);

return result;

}

result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

if (result) {

ALOGE("Could not start InputReader thread due to error %d.", result);

mDispatcherThread->requestExit();

return result;

}

return OK;

}

InputReader是由InputManager生成,同时还生成了两个线程,一个用于取InputDevice输入的信息,一个负责分发事件

void CursorInputMapper::process(const RawEvent* rawEvent) {

mCursorButtonAccumulator.process(rawEvent);

mCursorMotionAccumulator.process(rawEvent);

mCursorScrollAccumulator.process(rawEvent);

if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {

sync(rawEvent->when);

}

}

void CursorInputMapper::sync(nsecs_t when) {

......

// Synthesize key down from buttons if needed.

synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,

policyFlags, lastButtonState, currentButtonState);

// Send motion event.

if (downChanged || moved || scrolled || buttonsChanged) {

int32_t metaState = mContext->getGlobalMetaState();

int32_t buttonState = lastButtonState;

int32_t motionEventAction;

if (downChanged) {

motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;

} else if (down || mPointerController == NULL) {

motionEventAction = AMOTION_EVENT_ACTION_MOVE;

} else {

motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;

}

if (buttonsReleased) {

BitSet32 released(buttonsReleased);

while (!released.isEmpty()) {

int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());

buttonState &= ~actionButton;

NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,

AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,

metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,

displayId, 1, &pointerProperties, &pointerCoords,

mXPrecision, mYPrecision, downTime);

getListener()->notifyMotion(&releaseArgs);

}

}

NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,

motionEventAction, 0, 0, metaState, currentButtonState,

AMOTION_EVENT_EDGE_FLAG_NONE,

displayId, 1, &pointerProperties, &pointerCoords,

mXPrecision, mYPrecision, downTime);

getListener()->notifyMotion(&args);

......

// Synthesize key up from buttons if needed.

synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,

policyFlags, lastButtonState, currentButtonState);

mCursorMotionAccumulator.finishSync();

mCursorScrollAccumulator.finishSync();

}

InputReader管理着所有的InputDevice,针对不同的输入设备类型,对应不同的InputMapper类,鼠标类型是CursorInputMapper类,Cursor取事件的方法是process,在sync方法中进行处理。

static void synthesizeButtonKey(InputReaderContext* context, int32_t action,

nsecs_t when, int32_t deviceId, uint32_t source,

uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,

int32_t buttonState, int32_t keyCode) {

if (

(action == AKEY_EVENT_ACTION_DOWN

&& !(lastButtonState & buttonState)

&& (currentButtonState & buttonState))

|| (action == AKEY_EVENT_ACTION_UP

&& (lastButtonState & buttonState)

&& !(currentButtonState & buttonState))) {

NotifyKeyArgs args(when, deviceId, source, policyFlags,

action, 0, keyCode, 0, context->getGlobalMetaState(), when);

context->getListener()->notifyKey(&args);

}

}

static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,

nsecs_t when, int32_t deviceId, uint32_t source,

uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {

synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,

lastButtonState, currentButtonState,

AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);

synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,

lastButtonState, currentButtonState,

AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);

}

synthesizeButtonKeys对key进行合成,我们看到了熟悉的BACK键,context->getListener()->notifyKey(&key)

InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

......

int32_t keyCode = args->keyCode;

if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {

int32_t newKeyCode = AKEYCODE_UNKNOWN;

if (keyCode == AKEYCODE_DEL) {

newKeyCode = AKEYCODE_BACK;

} else if (keyCode == AKEYCODE_ENTER) {

newKeyCode = AKEYCODE_HOME;

}

if (newKeyCode != AKEYCODE_UNKNOWN) {

AutoMutex _l(mLock);

struct KeyReplacement replacement = {keyCode, args->deviceId};

mReplacedKeys.add(replacement, newKeyCode);

keyCode = newKeyCode;

metaState &= ~AMETA_META_ON;

}

} else if (args->action == AKEY_EVENT_ACTION_UP) {

// In order to maintain a consistent stream of up and down events, check to see if the key

// going up is one we've replaced in a down event and haven't yet replaced in an up event,

// even if the modifier was released between the down and the up events.

AutoMutex _l(mLock);

struct KeyReplacement replacement = {keyCode, args->deviceId};

ssize_t index = mReplacedKeys.indexOfKey(replacement);

if (index >= 0) {

keyCode = mReplacedKeys.valueAt(index);

mReplacedKeys.removeItemsAt(index);

metaState &= ~AMETA_META_ON;

}

}

KeyEvent event;

event.initialize(args->deviceId, args->source, args->action,

flags, keyCode, args->scanCode, metaState, 0,

args->downTime, args->eventTime);

mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

.......

}

context->getListener()取得的是针对InputDispatcher的一个封装,调用的是它的notifyKey,在InputManager构造方法中将InputDispatcher传给了InputReader。实际上调用的是

sp

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,

uint32_t& policyFlags) {

......

if (keyEventObj) {

wmActions = env->CallIntMethod(mServiceObj,

gServiceClassInfo.interceptKeyBeforeQueueing,

keyEventObj, policyFlags);

if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {

wmActions = 0;

}

android_view_KeyEvent_recycle(env, keyEventObj);

env->DeleteLocalRef(keyEventObj);

} else {

ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");

wmActions = 0;

}

handleInterceptActions(wmActions, when, /*byref*/ policyFlags);

} else {

if (interactive) {

policyFlags |= POLICY_FLAG_PASS_TO_USER;

}

}

}

sp的interceptKeyBeforeQueueing。InputManagerService的jni部分实现了InputDispatcherPolicyInterface的接口,jni部分调用了InputManagerService.java的interceptKeyBeforeQueueing方法,这样key事件传递到了Java世界。

private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);

}public interface WindowManagerCallbacks {

public void notifyConfigurationChanged();

public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);

public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);

public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);

public long notifyANR(InputApplicationHandle inputApplicationHandle,

InputWindowHandle inputWindowHandle, String reason);

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);

public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);

public long interceptKeyBeforeDispatching(InputWindowHandle focus,

KeyEvent event, int policyFlags);

public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,

KeyEvent event, int policyFlags);

public int getPointerLayer();

}

package com.android.server.wm;

final class InputMonitor implements InputManagerService.WindowManagerCallbacks

key事件通过mWindowManagerCallbacks.interceptKeyBeforeQueueing传递,mWindowManagerCallbacks是InputMonitor的对象,InputMonitor是wm包里的一个类,我们离windowManagerService已经很近了。

private final WindowManagerService mService;@Override

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);

}

mService就是WindowManagerService,mPolicy 就是PhoneWindowManager,最终我们来到了key值的处理和分发枢纽。

@Override

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

if (!mSystemBooted) {

// If we have not yet booted, don't let key events do anything.

return 0;

}

final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;

final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

final boolean canceled = event.isCanceled();

final int keyCode = event.getKeyCode();

final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;

......

switch (keyCode) {

case KeyEvent.KEYCODE_BACK: {

if (down) {

mBackKeyHandled = false;

if (hasLongPressOnBackBehavior()) {

Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);

msg.setAsynchronous(true);

mHandler.sendMessageDelayed(msg,

ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

}

} else {

boolean handled = mBackKeyHandled;

// Reset back key state

cancelPendingBackKeyAction();

// Don't pass back press to app if we've already handled it

if (handled) {

result &= ~ACTION_PASS_TO_USER;

}

}

break;

}

......

if (useHapticFeedback) {

performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);

}

if (isWakeKey) {

wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");

}

return result;

}

PhoneWindowManager对BACK按键的处理并没有什么特别的,PhoneWindowManager主要是对全局性的key进行处理,比如POWER、RECENT等,由于BACK按键对于View体系是非常重要的,事件肯定会分发到View层面进行进一步处理。把Key事件放进队列,我们回到InputDispatcher.cpp。

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {

......

mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);

bool needWake;

{ // acquire lock

mLock.lock();

if (shouldSendKeyToInputFilterLocked(args)) {

mLock.unlock();

policyFlags |= POLICY_FLAG_FILTERED;

if (!mPolicy->filterInputEvent(&event, policyFlags)) {

return; // event was consumed by the filter

}

mLock.lock();

}

int32_t repeatCount = 0;

KeyEntry* newEntry = new KeyEntry(args->eventTime,

args->deviceId, args->source, policyFlags,

args->action, flags, keyCode, args->scanCode,

metaState, repeatCount, args->downTime);

needWake = enqueueInboundEventLocked(newEntry);

mLock.unlock();

} // release lock

if (needWake) {

mLooper->wake();

}

}

将Key事件放进队列,然后呢?mLooper->wake()消费这个消息,不理解的可以看NativeMessageQueue

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {

bool needWake = mInboundQueue.isEmpty();

mInboundQueue.enqueueAtTail(entry);

traceInboundQueueLengthLocked();

InputDispatcher的enqueueInboundEventLocked方法将事件放进队列。

void InputReader::loopOnce() {

......

// Send out a message that the describes the changed input devices.

if (inputDevicesChanged) {

mPolicy->notifyInputDevicesChanged(inputDevices);

}

// Flush queued events out to the listener.

// This must happen outside of the lock because the listener could potentially call

// back into the InputReader's methods, such as getScanCodeState, or become blocked

// on another thread similarly waiting to acquire the InputReader lock thereby

// resulting in a deadlock. This situation is actually quite plausible because the

// listener is actually the input dispatcher, which calls into the window manager,

// which occasionally calls into the input reader.

mQueuedListener->flush();

}

bool InputDispatcherThread::threadLoop() {

mDispatcher->dispatchOnce();

return true;

}

void InputDispatcher::dispatchOnce() {

nsecs_t nextWakeupTime = LONG_LONG_MAX;

{ // acquire lock

AutoMutex _l(mLock);

mDispatcherIsAliveCondition.broadcast();

// Run a dispatch loop if there are no pending commands.

// The dispatch loop might enqueue commands to run afterwards.

if (!haveCommandsLocked()) {

dispatchOnceInnerLocked(&nextWakeupTime);

}

// Run all pending commands if there are any.

// If any commands were run then force the next poll to wake up immediately.

if (runCommandsLockedInterruptible()) {

nextWakeupTime = LONG_LONG_MIN;

}

} // release lock

// Wait for callback or timeout or wake. (make sure we round up, not down)

nsecs_t currentTime = now();

int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);

mLooper->pollOnce(timeoutMillis);

}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

......

// Inbound queue has at least one entry.

mPendingEvent = mInboundQueue.dequeueAtHead();

traceInboundQueueLengthLocked();

......

case EventEntry::TYPE_KEY: {

KeyEntry* typedEntry = static_cast(mPendingEvent);

if (isAppSwitchDue) {

if (isAppSwitchKeyEventLocked(typedEntry)) {

resetPendingAppSwitchLocked(true);

isAppSwitchDue = false;

} else if (dropReason == DROP_REASON_NOT_DROPPED) {

dropReason = DROP_REASON_APP_SWITCH;

}

}

if (dropReason == DROP_REASON_NOT_DROPPED

&& isStaleEventLocked(currentTime, typedEntry)) {

dropReason = DROP_REASON_STALE;

}

if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {

dropReason = DROP_REASON_BLOCKED;

}

done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);

break;

}

......

}

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,

EventEntry* eventEntry, const Vector& inputTargets) {

......

for (size_t i = 0; i < inputTargets.size(); i++) {

const InputTarget& inputTarget = inputTargets.itemAt(i);

ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);

if (connectionIndex >= 0) {

sp connection = mConnectionsByFd.valueAt(connectionIndex);

prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);

......

}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,

const sp& connection) {

......

while (connection->status == Connection::STATUS_NORMAL

&& !connection->outboundQueue.isEmpty()) {

DispatchEntry* dispatchEntry = connection->outboundQueue.head;

dispatchEntry->deliveryTime = currentTime;

// Publish the event.

status_t status;

EventEntry* eventEntry = dispatchEntry->eventEntry;

switch (eventEntry->type) {

case EventEntry::TYPE_KEY: {

KeyEntry* keyEntry = static_cast(eventEntry);

// Publish the key event.

status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,

keyEntry->deviceId, keyEntry->source,

dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,

keyEntry->keyCode, keyEntry->scanCode,

keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,

keyEntry->eventTime);

break;

}

之前我们介绍InputReader创建的时候,提到了InputManager创建了两个线程,一个是分发线程,一个是取事件的线程,在start中启动了他们,会调用到InputReader的loopOnce取得事件放入队列,放入队列的预处理之前已经分析,接下来是InputDispatcherThread循坏mDispatcher->dispatchOnce。dispatchOnce中dispatch一个消息

status_t InputPublisher::publishKeyEvent(

uint32_t seq,

int32_t deviceId,

int32_t source,

int32_t action,

int32_t flags,

int32_t keyCode,

int32_t scanCode,

int32_t metaState,

int32_t repeatCount,

nsecs_t downTime,

nsecs_t eventTime) {

.....

InputMessage msg;

msg.header.type = InputMessage::TYPE_KEY;

msg.body.key.seq = seq;

msg.body.key.deviceId = deviceId;

msg.body.key.source = source;

msg.body.key.action = action;

msg.body.key.flags = flags;

msg.body.key.keyCode = keyCode;

msg.body.key.scanCode = scanCode;

msg.body.key.metaState = metaState;

msg.body.key.repeatCount = repeatCount;

msg.body.key.downTime = downTime;

msg.body.key.eventTime = eventTime;

return mChannel->sendMessage(&msg);

}

最终在InputPublisher中由mChannel->sendMessage, mChannel是某个window和InputReader的一个桥梁,这里发消息应该是发给了一个window。

class Connection : public RefBase {

protected:

virtual ~Connection();

public:

enum Status {

// Everything is peachy.

STATUS_NORMAL,

// An unrecoverable communication error has occurred.

STATUS_BROKEN,

// The input channel has been unregistered.

STATUS_ZOMBIE

};

Status status;

sp inputChannel; // never null

sp inputWindowHandle; // may be null

bool monitor;

InputPublisher inputPublisher;

InputState inputState;

// True if the socket is full and no further events can be published until

// the application consumes some of the input.

bool inputPublisherBlocked;

// Queue of events that need to be published to the connection.

Queue outboundQueue;

// Queue of events that have been published to the connection but that have not

// yet received a "finished" response from the application.

Queue waitQueue;

explicit Connection(const sp& inputChannel,

const sp& inputWindowHandle, bool monitor);

inline const char* getInputChannelName() const { return inputChannel->getName().string(); }

const char* getWindowName() const;

const char* getStatusLabel() const;

DispatchEntry* findWaitQueueEntry(uint32_t seq);

};

Connection是InputDispatcher的一个内部类,通过registerInputChannel,那么在哪里建立了这种连接呢?

status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,

const sp& inputChannel,

const sp& inputWindowHandle, bool monitor) {

return mInputManager->getDispatcher()->registerInputChannel(

inputChannel, inputWindowHandle, monitor);

}

public void registerInputChannel(InputChannel inputChannel,

InputWindowHandle inputWindowHandle) {

if (inputChannel == null) {

throw new IllegalArgumentException("inputChannel must not be null.");

}

nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);

}

我找找到了InputManagerService.java这个源头

void openInputChannel(InputChannel outInputChannel) {

if (mInputChannel != null) {

throw new IllegalStateException("Window already has an input channel.");

}

String name = makeInputChannelName();

InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

mInputChannel = inputChannels[0];

mClientChannel = inputChannels[1];

mInputWindowHandle.inputChannel = inputChannels[0];

if (outInputChannel != null) {

mClientChannel.transferTo(outInputChannel);

mClientChannel.dispose();

mClientChannel = null;

} else {

// If the window died visible, we setup a dummy input channel, so that taps

// can still detected by input monitor channel, and we can relaunch the app.

// Create dummy event receiver that simply reports all events as handled.

mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);

}

mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);

}

WindowState中找到了有关调用,这个mService又是WindowsManagerService

public int addWindow(Session session, IWindow client, int seq,

WindowManager.LayoutParams attrs, int viewVisibility, int displayId,

Rect outContentInsets, Rect outStableInsets, Rect outOutsets,

InputChannel outInputChannel) {

......

final boolean openInputChannels = (outInputChannel != null

&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);

if (openInputChannels) {

win.openInputChannel(outInputChannel);

}

public View addStartingWindow(IBinder appToken, String packageName, int theme,

CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,

int icon, int logo, int windowFlags, Configuration overrideConfig) {

......

WindowManager wm = null;

View view = null;

try {

Context context = mContext;

if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName

+ ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="

+ Integer.toHexString(theme));

if (theme != context.getThemeResId() || labelRes != 0) {

try {

context = context.createPackageContext(packageName, 0);

context.setTheme(theme);

} catch (PackageManager.NameNotFoundException e) {

// Ignore

}

}

......

final PhoneWindow win = new PhoneWindow(context);

......

wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

view = win.getDecorView();

if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Adding starting window for "

+ packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));

wm.addView(view, params);

......

}

在每次addWindow的时候建立了一个连接,证实了我们的猜想。

1ab31e4f6a7cab9a272568907a096ee5.png

InputPublisher如何与消息系统建立联系,看一下时序图。

public void addView(View view, ViewGroup.LayoutParams params,

Display display, Window parentWindow) {

......

ViewRootImpl root;

View panelParentView = null;

synchronized (mLock) {

......

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);

mRoots.add(root);

mParams.add(wparams);

}

// do this last because it fires off messages to start doing things

try {

root.setView(view, wparams, panelParentView);

} catch (RuntimeException e) {

......

}

Android View体系中,Window包含了很多View, 包括一个DecorView和一个ViewGroup,之后添加进来的View,都会创建一个ViewRootImpl对应,让我们看看ViewRootImpl是干什么的?

/**

* The top of a view hierarchy, implementing the needed protocol between View

* and the WindowManager. This is for the most part an internal implementation

* detail of {@link WindowManagerGlobal}.

*

* {@hide}

*/

@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})

public final class ViewRootImpl implements ViewParent,

View.AttachInfo.Callbacks, ThreadedRenderer.HardwareDrawCallbacks

ViewRootImpl是WindowManager和View之间的桥梁,管理着View除视图外其他的部分,它实际上是一个Handler,它可以向DecorView分发事件,当然,AccessibilityService的部分也在这里处理。

setView(View view...){

......

if (mInputChannel != null) {

if (mInputQueueCallback != null) {

mInputQueue = new InputQueue();

mInputQueueCallback.onInputQueueCreated(mInputQueue);

}

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,

Looper.myLooper());

}

......

}

ViewRootImpl setView的时候会建立一个InputReceiver,当有inputEvent时触发。

final class WindowInputEventReceiver extends InputEventReceiver {

public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {

super(inputChannel, looper);

}

@Override

public void onInputEvent(InputEvent event) {

enqueueInputEvent(event, this, 0, true);

}

@Override

public void onBatchedInputEventPending() {

if (mUnbufferedInputDispatch) {

super.onBatchedInputEventPending();

} else {

scheduleConsumeBatchedInput();

}

}

@Override

public void dispose() {

unscheduleConsumeBatchedInput();

super.dispose();

}

}

void enqueueInputEvent(InputEvent event,

InputEventReceiver receiver, int flags, boolean processImmediately) {

......

if (processImmediately) {

doProcessInputEvents();

} else {

scheduleProcessInputEvents();

}

}

void doProcessInputEvents() {

// Deliver all pending input events in the queue.

while (mPendingInputEventHead != null) {

QueuedInputEvent q = mPendingInputEventHead;

mPendingInputEventHead = q.mNext;

if (mPendingInputEventHead == null) {

mPendingInputEventTail = null;

}

q.mNext = null;

......

deliverInputEvent(q);

}

......

}private void deliverInputEvent(QueuedInputEvent q) {

Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",

q.mEvent.getSequenceNumber());

if (mInputEventConsistencyVerifier != null) {

mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);

}

InputStage stage;

if (q.shouldSendToSynthesizer()) {

stage = mSyntheticInputStage;

} else {

stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;

}

if (stage != null) {

stage.deliver(q);

} else {

finishInputEvent(q);

}

}

public boolean shouldSkipIme() {

if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {

return true;

}

return mEvent instanceof MotionEvent

&& mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);

}mFirstInputStage = earlyPostInputStage;

这个stage很关键,shouldSkipIme返回true,因为没有软键盘,所以stage = earlyPostInputStage。

注意next参数是ViewPostImeInputStage,earlyPostInputStage的主要作用是将Key事件传递到native层的Activity(现在很多的Activity是用NativeActivity开发的),所以我们不走这里,我们走next.deliver,也就是ViewPostImeInputStage。

final class ViewPostImeInputStage extends InputStage {

public ViewPostImeInputStage(InputStage next) {

super(next);

}

@Override

protected int onProcess(QueuedInputEvent q) {

if (q.mEvent instanceof KeyEvent) {

return processKeyEvent(q);

} else {

final int source = q.mEvent.getSource();

if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {

return processPointerEvent(q);

} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {

return processTrackballEvent(q);

} else {

return processGenericMotionEvent(q);

}

}

}

@Override

protected void onDeliverToNext(QueuedInputEvent q) {

if (mUnbufferedInputDispatch

&& q.mEvent instanceof MotionEvent

&& ((MotionEvent)q.mEvent).isTouchEvent()

&& isTerminalInputEvent(q.mEvent)) {

mUnbufferedInputDispatch = false;

scheduleConsumeBatchedInput();

}

super.onDeliverToNext(q);

}

private int processKeyEvent(QueuedInputEvent q) {

final KeyEvent event = (KeyEvent)q.mEvent;

// Deliver the key to the view hierarchy.

if (mView.dispatchKeyEvent(event)) {

return FINISH_HANDLED;

}

key终于传递到了View hierarchy,也就是DecorView。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐