Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android:輸入系統(InputChannel)

Android:輸入系統(InputChannel)

編輯:關於Android編程

前面的“錘子快捷鍵”相關文章已經分析了輸入事件的讀取,處理,分發。我們知道事件的傳遞是以window為單位傳遞的,即server只負責將事件傳遞給某一個或者多個window,window然後再將事件傳遞給某一個具體的view。一個activity或者dialog對應一個window,但是事件只傳遞給合適的window,比如對於按鍵事件,就必須是獲得焦點的window,也就是說只能傳遞給一個window,通常是最上面的程序。找到了合適的window,然後就是將事件添加到window的Connection的事件隊列上。其實,到這為止輸入事件還只是在server端,即system_server這個進程裡,要想讓程序獲取到事件,肯定必須將事件信息傳遞到程序端的進程裡。這個就是Connection的實現問題了,這個connection的真正邏輯是InputChannel, InputChannel其實就是linux unix socket的一種封裝, unixsocket是linux的一種跨進程通信方式。系統創建InputChannel對即unix socket對,系統server端和程序client各只有其中一個,這樣通過unix socket就可以給對方發送消息,而這裡的事件就是通過這種方式從系統進程傳遞到程序進程的。整個系統框架圖如下:
這裡寫圖片描述

系統server端的InputChannel

系統InputChannel的整個處理邏輯如下:
這裡寫圖片描述

Server端 InputChannel的創建

Server端 InputChannel是在window被創建的時候創建的:

    //addWindow會創建一個channel對,其實上就是unix socket對,其中一個unix socket
    //通過傳入參數outInputChannel被傳遞到程序端,
    //另外一個unix socket保存在server的window中並注冊到native的InputManager
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
            //創建window的數據對象WindowState
            win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
            if (outInputChannel != null && (attrs.inputFeatures & 
                WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                String name = win.makeInputChannelName();
                //創建channel對,即會返回兩個InputChannel
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                //一個unix socket保存到window裡
                win.setInputChannel(inputChannels[0]);
                //另外一個unix socket傳遞到程序端
                inputChannels[1].transferTo(outInputChannel);
                //這個函數很重要,這個會將server端的unix socket注冊到native層
                //的InputManager,  win.mInputChannel就是上面的inputChannels[0]
                mInputManager.registerInputChannel(win.mInputChannel, 
                       win.mInputWindowHandle);
            }
        }
        return res;
}

public static InputChannel[] openInputChannelPair(String name) {
        return nativeOpenInputChannelPair(name);
}

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    sp serverChannel;
    sp clientChannel;
     //創建input channel對
    status_t result = InputChannel::openInputChannelPair(name, 
         serverChannel, clientChannel);
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    //創建inputChannel對應的java對象
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(serverChannel));
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            new NativeInputChannel(clientChannel));
    //將兩個channel放到channel數組中
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}
//InputTransport.cpp
status_t InputChannel::openInputChannelPair(const String8& name,
        sp& outServerChannel, sp& outClientChannel) {
    int sockets[2];
    //很早的android 版本是使用雙向管道實現的,而是現在是使用unix socket雙通道
    //來通信
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    //創建InputChannel,並把通信文件句柄傳入
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    //創建InputChannel,並把通信文件句柄傳入
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

Server端 InputChannel事件監聽器安裝

InputDispatcher要能夠發送事件數據,必須的要讓其知道對應的window的InputChannel,這個通過注冊實現的。

 public void registerInputChannel(InputChannel inputChannel,
            InputWindowHandle inputWindowHandle) {        
        nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp& inputChannel,
        const sp& inputWindowHandle, bool monitor) {
    //調用InputDispatcher的函數
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
        const sp& inputWindowHandle, bool monitor) {
    { // acquire lock
        AutoMutex _l(mLock);
        //這個將inputChannel封裝為Connection
        sp connection = new Connection(inputChannel, 
inputWindowHandle, monitor);
            //這個就是unix socket文件句柄
        int fd = inputChannel->getFd();
        //將connection保存到映射表中
        mConnectionsByFd.add(fd, connection);
        //監聽該unix socket文件,當unix socket有數據時即client發送消息過來了,
        //函數handleReceiveCallback就會被執行
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    return OK;
}

Server端的InputChannel事件數據發送

在上幾篇文章“錘子快捷鍵配置”中,已經講到了事件分發,並最後將事件放到了connection的事件隊列中,InputChannel事件發送就是從開始的

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();
    // Enqueue dispatch entries for the requested modes.
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_IS);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

    // 原來是空,現在不空,則立刻分發事件
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
} 

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp& connection) {
    //遍歷所有發送隊列中的事件
    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        //獲取最早的需要發送的事件
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast(eventEntry);

            //真正發送事件.
            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;
        }

        // Check the result.
        if (status) {
            if (status == WOULD_BLOCK) {
                if (connection->waitQueue.isEmpty()) {
                } else {
                    connection->inputPublisherBlocked = true;
                }
            }
            //發送成功,返回執行下一次循環
            return;
        }

        // 事件發送失敗,重新放進待發送隊列
        connection->outboundQueue.dequeue(dispatchEntry);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
    }
}

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;
    //將輸入事件轉化為unix socket通信的格式
    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;
    //調用unix socket消息發送機制
    return mChannel->sendMessage(&msg);
}

status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
do {
    //通過unix socket將事件數據發送到程序端
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    return OK;
}

程序client端的InputChannel

client的InputChannel相關的處理邏輯如下:
這裡寫圖片描述

Client 端的InputChannel創建

Client接受事件,肯定必須先獲得inputChannel,這個是在addWindow時系統返回回來的。

public void setView(View view, WindowManager.LayoutParams attrs, 
View panelParentView) {
        synchronized (this) {
                if ((mWindowAttributes.inputFeatures&
                   WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    mInputChannel = new InputChannel();
                }
                try {
                    //該函數會返回一個InputChannel
                    res = mWindowSession.addToDisplay(mWindow, mSeq,
                            mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mInputChannel);
                }
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    //為InputChannel注冊監聽器
                    mInputEventReceiver = new WindowInputEventReceiver(
                         mInputChannel,
                         Looper.myLooper());
                }
}

Client端的 InputChannel監聽器安裝

InputChannel監聽器安裝在WindowInputEventReceiver初始化的時候

final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
}
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
 }

static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    //獲取native層的InputChannel
    sp inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    //獲取java層InputEventReceiver對象的native層的消息隊列
    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        //創建native對應的InputEventReceiver對象
    sp receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    //這個是真正安裝監聽的函數
    status_t status = receiver->initialize();
    return reinterpret_cast(receiver.get());
}


status_t NativeInputEventReceiver::initialize() {
    //安裝監聽器
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
           //用looper監聽inputChannel對應的unix socket文件句柄
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        }
    }
}

int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}

int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) {
    { // acquire lock
        AutoMutex _l(mLock);
        //將監聽參數封裝
        Request request;
        request.fd = fd;
        request.ident = ident;
        //這個很重要,當被監聽的文件發生變化時就會調用該callback函數
        request.callback = callback;
        request.data = data;

        ssize_t requestIndex = mRequests.indexOfKey(fd);
        if (requestIndex < 0) {
            //epoll該文件,也就是講unix socket文件添加到監聽文件列表中
            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
            mRequests.add(fd, request);
        }
    } // release lock
    return 1;
}

Client端的InputChannel中的事件接收

從上面可以看出,Java的InputEventReceiver層的native層的NativeInputEventReceiver負責監聽事件,當有事件時,就會調用它。

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
        result = pollInner(timeoutMillis);
    }
}

int Looper::pollInner(int timeoutMillis) {
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    //等待消息
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeReadPipeFd) {
            if (epollEvents & EPOLLIN) {
                awoken();
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
                //將事件放到事件隊列上
                pushResponse(events, mRequests.valueAt(requestIndex));
            }
        }
    }
Done: ;
    //處理前面加入的response事件
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == ALOOPER_POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            // 下面的callback就是 NativeInputEventRecieverd
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);
            }
            response.request.callback.clear();
            result = ALOOPER_POLL_CALLBACK;
        }
    }
    return result;
}


int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {

if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        //處理事件
        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
}
    return 1;
}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        //從buffer中還原出事件
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
        if (!skipCallbacks) {
            jobject inputEventObj;
            switch (inputEvent->getType()) {
            case AINPUT_EVENT_TYPE_KEY:
                //轉換為java層的InputEvent
                inputEventObj = android_view_KeyEvent_fromNative(env,
                        static_cast(inputEvent));
                break;
            }
            if (inputEventObj) {
                //這個就會調用到java層的函數InputEventReceiver->dispatchInputEvent
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq,
 inputEventObj);
            }
        }
    }
}

Client端對輸入事件的處理

輸入事件,比如按鍵事件並不是全部被window的view處理了,比如Back鍵,如果此時系統輸入法是顯示的,其實該鍵首先會去關閉輸入法,而window的view是接收不到這個鍵的,這個就是事件處理器鏈實現的,這個鏈上又各種處理器,它們按照處理的優先順序添加咋鏈表上

輸入事件處理鏈

public abstract class InputEventReceiver {
    //native收到輸入事件是最終會回調到該函數
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }
}

   final class WindowInputEventReceiver extends InputEventReceiver {
        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }
    }

    void enqueueInputEvent(InputEvent event) {
        enqueueInputEvent(event, null, 0, false);
    }

    void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        mPendingInputEventCount += 1;
        if (processImmediately) {
            //處理事件
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }

    void doProcessInputEvents() {
        // 遍歷所有的輸入事件
        while (mPendingInputEventHead != null) {
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;

            mPendingInputEventCount -= 1;
            //處理事件
            deliverInputEvent(q);
        }
    }

    private void deliverInputEvent(QueuedInputEvent q) {
        try {
            //檢測ime相關module是否需要處理該輸入事件,比如back鍵,是需要先
            //讓IME處理,這個時候需要先交給mFirstPostImeInputStage處理
            InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            if (stage != null) {
                stage.deliver(q);
            } else {
                //
                finishInputEvent(q);
            }
        }
    }

       //大部分時候stage= mFirstInputStage,這個變量在最開始的時候賦值
       InputStage syntheticInputStage = new SyntheticInputStage();
       InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
       InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                  "aq:native-post-ime:" + counterSuffix);
       InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
       InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
       InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
       InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);
       mFirstInputStage = nativePreImeStage;
       mFirstPostImeInputStage = earlyPostImeStage;
abstract class InputStage { public final void deliver(QueuedInputEvent q) { if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) { //已經被處理了,則讓後面的處理 forward(q); } else if (shouldDropInputEvent(q)) { finish(q, false); } else { //沒有處理,自己開始處理該事件 apply(q, onProcess(q)); } } protected void apply(QueuedInputEvent q, int result) { if (result == FORWARD) { forward(q); } else if (result == FINISH_HANDLED) { finish(q, true); } } protected void forward(QueuedInputEvent q) { onDeliverToNext(q); } protected void onDeliverToNext(QueuedInputEvent q) { //如果下一個事件處理器不為空,則讓下一個事件處理器處理 if (mNext != null) { mNext.deliver(q); } else { //所有的都處理器都完成了處理,調用finish告知server端事件已經被處理 finishInputEvent(q); } } } //將事件發送給view的事件處理器是ViewPostImeInputStage final class ViewPostImeInputStage extends InputStage { @Override protected int onProcess(QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) { return processKeyEvent(q); } } private int processKeyEvent(QueuedInputEvent q) { final KeyEvent event = (KeyEvent)q.mEvent; if (event.getAction() != KeyEvent.ACTION_UP) { // If delivering a new key event, make sure the window is // now allowed to start updating. handleDispatchDoneAnimating(); } // 向view發送按鍵事件 if (mView.dispatchKeyEvent(event)) { return FINISH_HANDLED; } // 系統默認按鍵處理,比如CAMERA快捷鍵處理 if (mFallbackEventHandler.dispatchKeyEvent(event)) { return FINISH_HANDLED; } return FORWARD; } }

從上面的邏輯可以看出處理器的處理有限順序是:
NativePreImeInputStage->ViewPreImeInputStage-> ImeInputStage->
EarlyPostImeInputStage-> NativePostImeInputStage->ViewPostImeInputStage->
SyntheticInputStage

Back按鍵如何結束Activity

剛剛前面說到,view獲得輸入事件是由ViewPostImeInputStage傳遞過來的。ViewPostImeInputStage會將事件傳遞給activity的根View —DecorView

   private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (!isDestroyed()) {
                //首先讓callback處理,然後調用super的接口
                final Callback cb = getCallback() && mFeatureId < 0 ? 
cb.dispatchKeyEvent(event)
                        : super.dispatchKeyEvent(event);
                if (handled) {
                    return true;
                }
            }

            return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
                    : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
        }
   }

   //上面的getCallback的返回值就是Activity,故其有很高的優先級獲取並處理這些按鍵。
   public boolean onKeyDown(int keyCode, KeyEvent event)  {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (getApplicationInfo().targetSdkVersion
                    >= Build.VERSION_CODES.ECLAIR) {
            } else {
                //這個就是結束activity的函數
                onBackPressed();
            }
            return true;
        }
    }

如果非back按鍵,則會調用super即View.dispatchKeyEvent的接口,view的事件接收及處理就是從這開始的。

View如何獲取按鍵

由於DecorView繼承FrameLayout,它自然是一個ViewGroup,所以我們來看下ViewGroup的dispatchKeyEvent。

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onKeyEvent(event, 1);
        }

        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
            //調用view的接口
            if (super.dispatchKeyEvent(event)) {
                return true;
            }
        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
                == PFLAG_HAS_BOUNDS) {
            //向獲得焦點的view傳遞事件
            if (mFocused.dispatchKeyEvent(event)) {
                return true;
            }
        }
        return false;
    }

    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.dispatch(this, mAttachInfo != null
                ? mAttachInfo.mKeyDispatchState : null, this)) {
            return true;
        }
        return false;
    }

    public final boolean dispatch(Callback receiver, DispatcherState state,
            Object target) {
        switch (mAction) {
            case ACTION_DOWN: {
                mFlags &= ~FLAG_START_TRACKING;
                //這個就是我們的常見的onKeyDown,onKeyUp接口的調用
                boolean res = receiver.onKeyDown(mKeyCode, this);
                return res;
            }
        }
        return false;
    }

Camera等快捷鍵是如何傳遞處理的

如果view沒有處理按鍵,則最後會給mFallbackEventHandler一個機會處理按鍵,Camera等快捷鍵就是由這個handler處理的,下面來看看。

 public ViewRootImpl(Context context, Display display) {       
mFallbackEventHandler= PolicyManager.makeNewFallbackEventHandler(context);
}

public class Policy implements IPolicy {
public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
   return new PhoneFallbackEventHandler(context);
}
}

public class PhoneFallbackEventHandler implements FallbackEventHandler {
    public boolean dispatchKeyEvent(KeyEvent event) {

        final int action = event.getAction();
        final int keyCode = event.getKeyCode();

        if (action == KeyEvent.ACTION_DOWN) {
            return onKeyDown(keyCode, event);
        } else {
            return onKeyUp(keyCode, event);
        }
    }

    boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_CAMERA: {
                if (event.getRepeatCount() == 0) {
                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
                    //啟動拍照程序
                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
                            null, null, null, 0, null, null);
                }
                return true;
            }
        }
        return false;
    }

輸入事件處理完成通知

client將事件處理完了,必須通知server已經完成對該事件的處理,否則server一直在等待事件完成而不能發送後面的事件。

private void finishInputEvent(QueuedInputEvent q) {
        if (q.mReceiver != null) {
            boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;              
            // mReceiver是InputEventReciever
            q.mReceiver.finishInputEvent(q.mEvent, handled);
        }
        recycleQueuedInputEvent(q);
}

public abstract class InputEventReceiver {
    public final void finishInputEvent(InputEvent event, boolean handled) {
        {
            int index = mSeqMap.indexOfKey(event.getSequenceNumber());
            if (index < 0) {
            } else {
                //又調回native層
                nativeFinishInputEvent(mReceiverPtr, seq, handled);
            }
        }
        event.recycleIfNeededAfterDispatch();
    }
}


status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
    //告知server端client已經處理完成inputEvent
    status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
    return status;
}


status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
    size_t seqChainCount = mSeqChains.size();
    if (seqChainCount) {
        uint32_t currentSeq = seq;
        uint32_t chainSeqs[seqChainCount];
        size_t chainIndex = 0;
        for (size_t i = seqChainCount; i-- > 0; ) {
             const SeqChain& seqChain = mSeqChains.itemAt(i);
             if (seqChain.seq == currentSeq) {
                 currentSeq = seqChain.chain;
                 chainSeqs[chainIndex++] = currentSeq;
                 mSeqChains.removeAt(i);
             }
        }
        status_t status = OK;
        while (!status && chainIndex-- > 0) {
            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
        }
    }

    // Send finished signal for the last message in the batch.
    return sendUnchainedFinishedSignal(seq, handled);
}

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
    InputMessage msg;
    msg.header.type = InputMessage::TYPE_FINISHED;
    msg.body.finished.seq = seq;
    msg.body.finished.handled = handled;
    return mChannel->sendMessage(&msg);
}

//這個和server端發送事件過來一樣的,只不過這次是client發送消息給server
status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
    do {
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    return OK;
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved