blob: 80c4871e4714707451341df72e1991d2a4c5dec1 [file] [log] [blame]
Jeff Brown46b9ac02010-04-22 18:58:52 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "InputQueue-JNI"
18
19//#define LOG_NDEBUG 0
20
21// Log debug messages about the dispatch cycle.
Jeff Brown349703e2010-06-22 01:27:15 -070022#define DEBUG_DISPATCH_CYCLE 0
Jeff Brown46b9ac02010-04-22 18:58:52 -070023
Jeff Brown9c3cda02010-06-15 01:31:58 -070024// Log debug messages about registrations.
Jeff Brown349703e2010-06-22 01:27:15 -070025#define DEBUG_REGISTRATION 0
Jeff Brown9c3cda02010-06-15 01:31:58 -070026
Jeff Brown46b9ac02010-04-22 18:58:52 -070027
28#include "JNIHelp.h"
29
30#include <android_runtime/AndroidRuntime.h>
31#include <utils/Log.h>
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070032#include <utils/Looper.h>
Jeff Brown46b9ac02010-04-22 18:58:52 -070033#include <utils/KeyedVector.h>
34#include <utils/threads.h>
35#include <ui/InputTransport.h>
36#include "android_os_MessageQueue.h"
37#include "android_view_InputChannel.h"
38#include "android_view_KeyEvent.h"
39#include "android_view_MotionEvent.h"
40
41namespace android {
42
43// ----------------------------------------------------------------------------
44
45static struct {
46 jclass clazz;
47
48 jmethodID dispatchKeyEvent;
49 jmethodID dispatchMotionEvent;
50} gInputQueueClassInfo;
51
52// ----------------------------------------------------------------------------
53
54class NativeInputQueue {
55public:
56 NativeInputQueue();
Jeff Brown9c3cda02010-06-15 01:31:58 -070057 ~NativeInputQueue();
Jeff Brown46b9ac02010-04-22 18:58:52 -070058
59 status_t registerInputChannel(JNIEnv* env, jobject inputChannelObj,
60 jobject inputHandlerObj, jobject messageQueueObj);
61
62 status_t unregisterInputChannel(JNIEnv* env, jobject inputChannelObj);
63
Jeff Brown3915bb82010-11-05 15:02:16 -070064 status_t finished(JNIEnv* env, jlong finishedToken, bool handled, bool ignoreSpuriousFinish);
Jeff Brown46b9ac02010-04-22 18:58:52 -070065
66private:
67 class Connection : public RefBase {
68 protected:
69 virtual ~Connection();
70
71 public:
72 enum Status {
73 // Everything is peachy.
74 STATUS_NORMAL,
75 // The input channel has been unregistered.
76 STATUS_ZOMBIE
77 };
78
Jeff Brown2cbecea2010-08-17 15:59:26 -070079 Connection(uint16_t id,
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070080 const sp<InputChannel>& inputChannel, const sp<Looper>& looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -070081
Jeff Brown9c3cda02010-06-15 01:31:58 -070082 inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
Jeff Brown46b9ac02010-04-22 18:58:52 -070083
Jeff Brown2cbecea2010-08-17 15:59:26 -070084 // A unique id for this connection.
85 uint16_t id;
86
Jeff Brown46b9ac02010-04-22 18:58:52 -070087 Status status;
88
89 sp<InputChannel> inputChannel;
90 InputConsumer inputConsumer;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070091 sp<Looper> looper;
Jeff Brown46b9ac02010-04-22 18:58:52 -070092 jobject inputHandlerObjGlobal;
93 PreallocatedInputEventFactory inputEventFactory;
94
95 // The sequence number of the current event being dispatched.
96 // This is used as part of the finished token as a way to determine whether the finished
97 // token is still valid before sending a finished signal back to the publisher.
Jeff Brown2cbecea2010-08-17 15:59:26 -070098 uint16_t messageSeqNum;
Jeff Brown46b9ac02010-04-22 18:58:52 -070099
100 // True if a message has been received from the publisher but not yet finished.
101 bool messageInProgress;
102 };
103
104 Mutex mLock;
Jeff Brown2cbecea2010-08-17 15:59:26 -0700105 uint16_t mNextConnectionId;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700106 KeyedVector<int32_t, sp<Connection> > mConnectionsByReceiveFd;
107
Jeff Brown2cbecea2010-08-17 15:59:26 -0700108 ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
109
Jeff Brown46b9ac02010-04-22 18:58:52 -0700110 static void handleInputChannelDisposed(JNIEnv* env,
111 jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
112
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700113 static int handleReceiveCallback(int receiveFd, int events, void* data);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700114
Jeff Brown2cbecea2010-08-17 15:59:26 -0700115 static jlong generateFinishedToken(int32_t receiveFd,
116 uint16_t connectionId, uint16_t messageSeqNum);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700117
118 static void parseFinishedToken(jlong finishedToken,
Jeff Brown2cbecea2010-08-17 15:59:26 -0700119 int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700120};
121
122// ----------------------------------------------------------------------------
123
Jeff Brown2cbecea2010-08-17 15:59:26 -0700124NativeInputQueue::NativeInputQueue() :
125 mNextConnectionId(0) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700126}
127
128NativeInputQueue::~NativeInputQueue() {
129}
130
131status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,
132 jobject inputHandlerObj, jobject messageQueueObj) {
133 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
134 inputChannelObj);
135 if (inputChannel == NULL) {
136 LOGW("Input channel is not initialized.");
137 return BAD_VALUE;
138 }
139
Jeff Brown9c3cda02010-06-15 01:31:58 -0700140#if DEBUG_REGISTRATION
141 LOGD("channel '%s' - Registered", inputChannel->getName().string());
142#endif
143
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700144 sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700145
Jeff Brown46b9ac02010-04-22 18:58:52 -0700146 { // acquire lock
147 AutoMutex _l(mLock);
148
Jeff Brown2cbecea2010-08-17 15:59:26 -0700149 if (getConnectionIndex(inputChannel) >= 0) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700150 LOGW("Attempted to register already registered input channel '%s'",
151 inputChannel->getName().string());
152 return BAD_VALUE;
153 }
154
Jeff Brown2cbecea2010-08-17 15:59:26 -0700155 uint16_t connectionId = mNextConnectionId++;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700156 sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700157 status_t result = connection->inputConsumer.initialize();
158 if (result) {
159 LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
160 inputChannel->getName().string(), result);
161 return result;
162 }
163
164 connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
165
Jeff Brown2cbecea2010-08-17 15:59:26 -0700166 int32_t receiveFd = inputChannel->getReceivePipeFd();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700167 mConnectionsByReceiveFd.add(receiveFd, connection);
Jeff Brown2cbecea2010-08-17 15:59:26 -0700168
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700169 looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700170 } // release lock
171
172 android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
173 handleInputChannelDisposed, this);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700174 return OK;
175}
176
177status_t NativeInputQueue::unregisterInputChannel(JNIEnv* env, jobject inputChannelObj) {
178 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
179 inputChannelObj);
180 if (inputChannel == NULL) {
181 LOGW("Input channel is not initialized.");
182 return BAD_VALUE;
183 }
184
Jeff Brown9c3cda02010-06-15 01:31:58 -0700185#if DEBUG_REGISTRATION
186 LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
187#endif
188
Jeff Brown46b9ac02010-04-22 18:58:52 -0700189 { // acquire lock
190 AutoMutex _l(mLock);
191
Jeff Brown2cbecea2010-08-17 15:59:26 -0700192 ssize_t connectionIndex = getConnectionIndex(inputChannel);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700193 if (connectionIndex < 0) {
194 LOGW("Attempted to unregister already unregistered input channel '%s'",
195 inputChannel->getName().string());
196 return BAD_VALUE;
197 }
198
Jeff Brown2cbecea2010-08-17 15:59:26 -0700199 sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700200 mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
201
202 connection->status = Connection::STATUS_ZOMBIE;
203
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700204 connection->looper->removeFd(inputChannel->getReceivePipeFd());
Jeff Brown2cbecea2010-08-17 15:59:26 -0700205
Jeff Brown46b9ac02010-04-22 18:58:52 -0700206 env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
207 connection->inputHandlerObjGlobal = NULL;
Jeff Brown2cbecea2010-08-17 15:59:26 -0700208
209 if (connection->messageInProgress) {
210 LOGI("Sending finished signal for input channel '%s' since it is being unregistered "
211 "while an input message is still in progress.",
212 connection->getInputChannelName());
213 connection->messageInProgress = false;
Jeff Brown3915bb82010-11-05 15:02:16 -0700214 connection->inputConsumer.sendFinishedSignal(false); // ignoring result
Jeff Brown2cbecea2010-08-17 15:59:26 -0700215 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700216 } // release lock
217
218 android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700219 return OK;
220}
221
Jeff Brown2cbecea2010-08-17 15:59:26 -0700222ssize_t NativeInputQueue::getConnectionIndex(const sp<InputChannel>& inputChannel) {
223 ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
224 if (connectionIndex >= 0) {
225 sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
226 if (connection->inputChannel.get() == inputChannel.get()) {
227 return connectionIndex;
228 }
229 }
230
231 return -1;
232}
233
Jeff Brown3915bb82010-11-05 15:02:16 -0700234status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken,
235 bool handled, bool ignoreSpuriousFinish) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700236 int32_t receiveFd;
Jeff Brown2cbecea2010-08-17 15:59:26 -0700237 uint16_t connectionId;
238 uint16_t messageSeqNum;
239 parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700240
241 { // acquire lock
242 AutoMutex _l(mLock);
243
244 ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
245 if (connectionIndex < 0) {
246 if (! ignoreSpuriousFinish) {
Jeff Brown2cbecea2010-08-17 15:59:26 -0700247 LOGI("Ignoring finish signal on channel that is no longer registered.");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700248 }
249 return DEAD_OBJECT;
250 }
251
252 sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
Jeff Brown2cbecea2010-08-17 15:59:26 -0700253 if (connectionId != connection->id) {
254 if (! ignoreSpuriousFinish) {
255 LOGI("Ignoring finish signal on channel that is no longer registered.");
256 }
257 return DEAD_OBJECT;
258 }
259
Jeff Brown46b9ac02010-04-22 18:58:52 -0700260 if (messageSeqNum != connection->messageSeqNum || ! connection->messageInProgress) {
261 if (! ignoreSpuriousFinish) {
Jeff Brown2cbecea2010-08-17 15:59:26 -0700262 LOGW("Attempted to finish input twice on channel '%s'. "
263 "finished messageSeqNum=%d, current messageSeqNum=%d, messageInProgress=%d",
264 connection->getInputChannelName(),
265 messageSeqNum, connection->messageSeqNum, connection->messageInProgress);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700266 }
267 return INVALID_OPERATION;
268 }
269
270 connection->messageInProgress = false;
271
Jeff Brown3915bb82010-11-05 15:02:16 -0700272 status_t status = connection->inputConsumer.sendFinishedSignal(handled);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700273 if (status) {
274 LOGW("Failed to send finished signal on channel '%s'. status=%d",
275 connection->getInputChannelName(), status);
276 return status;
277 }
278
279#if DEBUG_DISPATCH_CYCLE
280 LOGD("channel '%s' ~ Finished event.",
281 connection->getInputChannelName());
282#endif
283 } // release lock
284
285 return OK;
286}
287
288void NativeInputQueue::handleInputChannelDisposed(JNIEnv* env,
289 jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
290 LOGW("Input channel object '%s' was disposed without first being unregistered with "
291 "the input queue!", inputChannel->getName().string());
292
293 NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
294 q->unregisterInputChannel(env, inputChannelObj);
295}
296
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700297int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700298 NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
299 JNIEnv* env = AndroidRuntime::getJNIEnv();
300
301 sp<Connection> connection;
302 InputEvent* inputEvent;
303 jobject inputHandlerObjLocal;
304 jlong finishedToken;
305 { // acquire lock
306 AutoMutex _l(q->mLock);
307
308 ssize_t connectionIndex = q->mConnectionsByReceiveFd.indexOfKey(receiveFd);
309 if (connectionIndex < 0) {
310 LOGE("Received spurious receive callback for unknown input channel. "
311 "fd=%d, events=0x%x", receiveFd, events);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700312 return 0; // remove the callback
Jeff Brown46b9ac02010-04-22 18:58:52 -0700313 }
314
315 connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700316 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700317 LOGE("channel '%s' ~ Publisher closed input channel or an error occurred. "
318 "events=0x%x", connection->getInputChannelName(), events);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700319 return 0; // remove the callback
Jeff Brown46b9ac02010-04-22 18:58:52 -0700320 }
321
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700322 if (! (events & ALOOPER_EVENT_INPUT)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700323 LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
324 "events=0x%x", connection->getInputChannelName(), events);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700325 return 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700326 }
327
328 status_t status = connection->inputConsumer.receiveDispatchSignal();
329 if (status) {
330 LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
331 connection->getInputChannelName(), status);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700332 return 0; // remove the callback
Jeff Brown46b9ac02010-04-22 18:58:52 -0700333 }
334
335 if (connection->messageInProgress) {
336 LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
337 connection->getInputChannelName());
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700338 return 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700339 }
340
341 status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
342 if (status) {
343 LOGW("channel '%s' ~ Failed to consume input event. status=%d",
344 connection->getInputChannelName(), status);
Jeff Brown3915bb82010-11-05 15:02:16 -0700345 connection->inputConsumer.sendFinishedSignal(false);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700346 return 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700347 }
348
349 connection->messageInProgress = true;
350 connection->messageSeqNum += 1;
351
Jeff Brown2cbecea2010-08-17 15:59:26 -0700352 finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700353
354 inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal);
355 } // release lock
356
357 // Invoke the handler outside of the lock.
358 //
359 // Note: inputEvent is stored in a field of the connection object which could potentially
360 // become disposed due to the input channel being unregistered concurrently.
361 // For this reason, we explicitly keep the connection object alive by holding
362 // a strong pointer to it within this scope. We also grabbed a local reference to
363 // the input handler object itself for the same reason.
364
365 int32_t inputEventType = inputEvent->getType();
Jeff Brown46b9ac02010-04-22 18:58:52 -0700366
367 jobject inputEventObj;
368 jmethodID dispatchMethodId;
369 switch (inputEventType) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700370 case AINPUT_EVENT_TYPE_KEY:
Jeff Brown46b9ac02010-04-22 18:58:52 -0700371#if DEBUG_DISPATCH_CYCLE
372 LOGD("channel '%s' ~ Received key event.", connection->getInputChannelName());
373#endif
374 inputEventObj = android_view_KeyEvent_fromNative(env,
375 static_cast<KeyEvent*>(inputEvent));
376 dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent;
377 break;
378
Jeff Brownc5ed5912010-07-14 18:48:53 -0700379 case AINPUT_EVENT_TYPE_MOTION:
Jeff Brown46b9ac02010-04-22 18:58:52 -0700380#if DEBUG_DISPATCH_CYCLE
381 LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName());
382#endif
Jeff Brown2ed24622011-03-14 19:39:54 -0700383 inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700384 static_cast<MotionEvent*>(inputEvent));
385 dispatchMethodId = gInputQueueClassInfo.dispatchMotionEvent;
386 break;
387
388 default:
389 assert(false); // InputConsumer should prevent this from ever happening
390 inputEventObj = NULL;
391 }
392
393 if (! inputEventObj) {
394 LOGW("channel '%s' ~ Failed to obtain DVM event object.",
395 connection->getInputChannelName());
396 env->DeleteLocalRef(inputHandlerObjLocal);
Jeff Brown3915bb82010-11-05 15:02:16 -0700397 q->finished(env, finishedToken, false, false);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700398 return 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700399 }
400
401#if DEBUG_DISPATCH_CYCLE
402 LOGD("Invoking input handler.");
403#endif
404 env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
405 dispatchMethodId, inputHandlerObjLocal, inputEventObj,
Jeff Brownc5ed5912010-07-14 18:48:53 -0700406 jlong(finishedToken));
Jeff Brown46b9ac02010-04-22 18:58:52 -0700407#if DEBUG_DISPATCH_CYCLE
408 LOGD("Returned from input handler.");
409#endif
410
411 if (env->ExceptionCheck()) {
412 LOGE("An exception occurred while invoking the input handler for an event.");
413 LOGE_EX(env);
414 env->ExceptionClear();
415
Jeff Brown3915bb82010-11-05 15:02:16 -0700416 q->finished(env, finishedToken, false, true /*ignoreSpuriousFinish*/);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700417 }
418
419 env->DeleteLocalRef(inputEventObj);
420 env->DeleteLocalRef(inputHandlerObjLocal);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700421 return 1;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700422}
423
Jeff Brown2cbecea2010-08-17 15:59:26 -0700424jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
425 uint16_t messageSeqNum) {
426 return (jlong(receiveFd) << 32) | (jlong(connectionId) << 16) | jlong(messageSeqNum);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700427}
428
429void NativeInputQueue::parseFinishedToken(jlong finishedToken,
Jeff Brown2cbecea2010-08-17 15:59:26 -0700430 int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700431 *outReceiveFd = int32_t(finishedToken >> 32);
Jeff Brown2cbecea2010-08-17 15:59:26 -0700432 *outConnectionId = uint16_t(finishedToken >> 16);
433 *outMessageIndex = uint16_t(finishedToken);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700434}
435
436// ----------------------------------------------------------------------------
437
Jeff Brown2cbecea2010-08-17 15:59:26 -0700438NativeInputQueue::Connection::Connection(uint16_t id,
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700439 const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
Jeff Brown2cbecea2010-08-17 15:59:26 -0700440 id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700441 looper(looper), inputHandlerObjGlobal(NULL),
Jeff Brown46b9ac02010-04-22 18:58:52 -0700442 messageSeqNum(0), messageInProgress(false) {
443}
444
445NativeInputQueue::Connection::~Connection() {
446}
447
448// ----------------------------------------------------------------------------
449
450static NativeInputQueue gNativeInputQueue;
451
452static void android_view_InputQueue_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
453 jobject inputChannelObj, jobject inputHandlerObj, jobject messageQueueObj) {
454 status_t status = gNativeInputQueue.registerInputChannel(
455 env, inputChannelObj, inputHandlerObj, messageQueueObj);
Jeff Brownace999b2010-07-16 15:38:03 -0700456
Jeff Brown46b9ac02010-04-22 18:58:52 -0700457 if (status) {
458 jniThrowRuntimeException(env, "Failed to register input channel. "
459 "Check logs for details.");
460 }
461}
462
463static void android_view_InputQueue_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
464 jobject inputChannelObj) {
465 status_t status = gNativeInputQueue.unregisterInputChannel(env, inputChannelObj);
Jeff Brownace999b2010-07-16 15:38:03 -0700466
Jeff Brown46b9ac02010-04-22 18:58:52 -0700467 if (status) {
468 jniThrowRuntimeException(env, "Failed to unregister input channel. "
469 "Check logs for details.");
470 }
471}
472
473static void android_view_InputQueue_nativeFinished(JNIEnv* env, jclass clazz,
Jeff Brown3915bb82010-11-05 15:02:16 -0700474 jlong finishedToken, bool handled) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700475 status_t status = gNativeInputQueue.finished(
Jeff Brown3915bb82010-11-05 15:02:16 -0700476 env, finishedToken, handled, false /*ignoreSpuriousFinish*/);
Jeff Brownace999b2010-07-16 15:38:03 -0700477
478 // We ignore the case where an event could not be finished because the input channel
479 // was no longer registered (DEAD_OBJECT) since it is a common race that can occur
480 // during application shutdown. The input dispatcher recovers gracefully anyways.
481 if (status != OK && status != DEAD_OBJECT) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700482 jniThrowRuntimeException(env, "Failed to finish input event. "
483 "Check logs for details.");
484 }
485}
486
487// ----------------------------------------------------------------------------
488
489static JNINativeMethod gInputQueueMethods[] = {
490 /* name, signature, funcPtr */
491 { "nativeRegisterInputChannel",
492 "(Landroid/view/InputChannel;Landroid/view/InputHandler;Landroid/os/MessageQueue;)V",
493 (void*)android_view_InputQueue_nativeRegisterInputChannel },
494 { "nativeUnregisterInputChannel",
495 "(Landroid/view/InputChannel;)V",
496 (void*)android_view_InputQueue_nativeUnregisterInputChannel },
Jeff Brown3915bb82010-11-05 15:02:16 -0700497 { "nativeFinished", "(JZ)V",
Jeff Brown46b9ac02010-04-22 18:58:52 -0700498 (void*)android_view_InputQueue_nativeFinished }
499};
500
501#define FIND_CLASS(var, className) \
502 var = env->FindClass(className); \
503 LOG_FATAL_IF(! var, "Unable to find class " className); \
504 var = jclass(env->NewGlobalRef(var));
505
506#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \
507 var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \
508 LOG_FATAL_IF(! var, "Unable to find static method " methodName);
509
510int register_android_view_InputQueue(JNIEnv* env) {
511 int res = jniRegisterNativeMethods(env, "android/view/InputQueue",
512 gInputQueueMethods, NELEM(gInputQueueMethods));
513 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
514
515 FIND_CLASS(gInputQueueClassInfo.clazz, "android/view/InputQueue");
516
517 GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchKeyEvent, gInputQueueClassInfo.clazz,
518 "dispatchKeyEvent",
Jeff Brownc5ed5912010-07-14 18:48:53 -0700519 "(Landroid/view/InputHandler;Landroid/view/KeyEvent;J)V");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700520
521 GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchMotionEvent, gInputQueueClassInfo.clazz,
522 "dispatchMotionEvent",
Jeff Brownc5ed5912010-07-14 18:48:53 -0700523 "(Landroid/view/InputHandler;Landroid/view/MotionEvent;J)V");
Jeff Brown46b9ac02010-04-22 18:58:52 -0700524 return 0;
525}
526
527} // namespace android