編輯:關於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就可以給對方發送消息,而這裡的事件就是通過這種方式從系統進程傳遞到程序進程的。整個系統框架圖如下:

系統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;
}
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;
}
在上幾篇文章“錘子快捷鍵配置”中,已經講到了事件分發,並最後將事件放到了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,這個是在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());
}
}
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;
}
從上面可以看出,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);
}
}
}
}
輸入事件,比如按鍵事件並不是全部被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
剛剛前面說到,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的事件接收及處理就是從這開始的。
由於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;
}
如果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;
}
淺談Android官方MVP架構解讀
綜述對於MVP (Model View Presenter)架構是從著名的MVC(Model View Controller)架構演變而來的。而對於Android應用的開
Android自定義SwipeRefreshLayout高仿微信朋友圈下拉刷新
上一篇文章裡把SwipeRefreshLayout的原理簡單過了一下,大致了解了其工作原理,不熟悉的可以去看一下:http://www.jb51.net/article/
Android中刪除Preference詳解
Android的設置界面實現比較簡單,有時甚至只需要使用一個簡單的xml文件即可.聲明簡單,但是如何從PreferenceScreen或者PreferenceCatego
詳解Android首選項框架的使用實例
首選項這個名詞對於熟悉Android的朋友們一定不會感到陌生,它經常用來設置軟件的運行參數。Android提供了一種健壯並且靈活的框架來處理首選項。它提供了簡單的API來