Android 源码分析鼠标事件传递

来源:互联网 发布:苹果硬盘彻底删除数据 编辑:程序博客网 时间:2024/05/24 04:17

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<EventHubInterface>& eventHub,        const sp<InputReaderPolicyInterface>& readerPolicy,        const sp<InputDispatcherPolicyInterface>& 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<EventHubInterface>& eventHub,        const sp<InputReaderPolicyInterface>& readerPolicy,        const sp<InputDispatcherPolicyInterface>& 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<InputDispatcherPolicyInterface>

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<InputDispatcherPolicyInterface>的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<KeyEntry*>(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<InputTarget>& 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> connection = mConnectionsByFd.valueAt(connectionIndex);            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);......}

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,        const sp<Connection>& 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<KeyEntry*>(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> inputChannel; // never null        sp<InputWindowHandle> 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<DispatchEntry> outboundQueue;        // Queue of events that have been published to the connection but that have not        // yet received a "finished" response from the application.        Queue<DispatchEntry> waitQueue;        explicit Connection(const sp<InputChannel>& inputChannel,                const sp<InputWindowHandle>& 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>& inputChannel,        const sp<InputWindowHandle>& 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的时候建立了一个连接,证实了我们的猜想。



消息系统这里不再分析,有兴趣的参考这篇文章http://www.cnblogs.com/TaigaCon/p/4750349.html
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。

1 0
原创粉丝点击