blob: 9501cf225293afa09a49d6482f9e3a513caa8e7c [file] [log] [blame]
Jeff Brown32cbc38552011-12-01 14:01:49 -08001/*
2 * Copyright (C) 2011 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 "InputEventReceiver"
18
19//#define LOG_NDEBUG 0
20
21// Log debug messages about the dispatch cycle.
22#define DEBUG_DISPATCH_CYCLE 0
23
24
25#include "JNIHelp.h"
26
27#include <android_runtime/AndroidRuntime.h>
28#include <utils/Log.h>
29#include <utils/Looper.h>
Jeff Brown32cbc38552011-12-01 14:01:49 -080030#include <utils/threads.h>
Mathias Agopianb93a03f82012-02-17 15:34:57 -080031#include <androidfw/InputTransport.h>
Jeff Brown32cbc38552011-12-01 14:01:49 -080032#include "android_os_MessageQueue.h"
33#include "android_view_InputChannel.h"
34#include "android_view_KeyEvent.h"
35#include "android_view_MotionEvent.h"
36
37namespace android {
38
39static struct {
40 jclass clazz;
41
42 jmethodID dispatchInputEvent;
Jeff Brown072ec962012-02-07 14:46:57 -080043 jmethodID dispatchBatchedInputEventPending;
Jeff Brown32cbc38552011-12-01 14:01:49 -080044} gInputEventReceiverClassInfo;
45
46
Jeff Brown80a1de12012-05-31 16:23:11 -070047class NativeInputEventReceiver : public LooperCallback {
Jeff Brown32cbc38552011-12-01 14:01:49 -080048public:
49 NativeInputEventReceiver(JNIEnv* env,
50 jobject receiverObj, const sp<InputChannel>& inputChannel,
Jeff Brown603b4452012-04-06 17:39:41 -070051 const sp<MessageQueue>& messageQueue);
Jeff Brown32cbc38552011-12-01 14:01:49 -080052
53 status_t initialize();
Jeff Brown80a1de12012-05-31 16:23:11 -070054 void dispose();
Jeff Brown072ec962012-02-07 14:46:57 -080055 status_t finishInputEvent(uint32_t seq, bool handled);
Jeff Brown771526c2012-04-27 15:13:25 -070056 status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime);
Jeff Brown32cbc38552011-12-01 14:01:49 -080057
58protected:
59 virtual ~NativeInputEventReceiver();
60
61private:
62 jobject mReceiverObjGlobal;
63 InputConsumer mInputConsumer;
Jeff Brown603b4452012-04-06 17:39:41 -070064 sp<MessageQueue> mMessageQueue;
Jeff Brown32cbc38552011-12-01 14:01:49 -080065 PreallocatedInputEventFactory mInputEventFactory;
Jeff Brown072ec962012-02-07 14:46:57 -080066 bool mBatchedInputEventPending;
Jeff Brown32cbc38552011-12-01 14:01:49 -080067
68 const char* getInputChannelName() {
69 return mInputConsumer.getChannel()->getName().string();
70 }
Jeff Brown3bdcdd82012-04-10 20:36:07 -070071
Jeff Brown80a1de12012-05-31 16:23:11 -070072 virtual int handleEvent(int receiveFd, int events, void* data);
Jeff Brown32cbc38552011-12-01 14:01:49 -080073};
74
75
76NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
Jeff Brown603b4452012-04-06 17:39:41 -070077 jobject receiverObj, const sp<InputChannel>& inputChannel,
78 const sp<MessageQueue>& messageQueue) :
Jeff Brown32cbc38552011-12-01 14:01:49 -080079 mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
Jeff Brown603b4452012-04-06 17:39:41 -070080 mInputConsumer(inputChannel), mMessageQueue(messageQueue),
Jeff Brown072ec962012-02-07 14:46:57 -080081 mBatchedInputEventPending(false) {
Jeff Brown32cbc38552011-12-01 14:01:49 -080082#if DEBUG_DISPATCH_CYCLE
Steve Block5baa3a62011-12-20 16:23:08 +000083 ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
Jeff Brown32cbc38552011-12-01 14:01:49 -080084#endif
85}
86
87NativeInputEventReceiver::~NativeInputEventReceiver() {
Jeff Brown32cbc38552011-12-01 14:01:49 -080088 JNIEnv* env = AndroidRuntime::getJNIEnv();
89 env->DeleteGlobalRef(mReceiverObjGlobal);
90}
91
92status_t NativeInputEventReceiver::initialize() {
Jeff Brown91e32892012-02-14 15:56:29 -080093 int receiveFd = mInputConsumer.getChannel()->getFd();
Jeff Brown80a1de12012-05-31 16:23:11 -070094 mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
Jeff Brown32cbc38552011-12-01 14:01:49 -080095 return OK;
96}
97
Jeff Brown80a1de12012-05-31 16:23:11 -070098void NativeInputEventReceiver::dispose() {
99#if DEBUG_DISPATCH_CYCLE
100 ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
101#endif
102
103 mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd());
104}
105
Jeff Brown072ec962012-02-07 14:46:57 -0800106status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800107#if DEBUG_DISPATCH_CYCLE
Jeff Brown072ec962012-02-07 14:46:57 -0800108 ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
Jeff Brown32cbc38552011-12-01 14:01:49 -0800109#endif
Jeff Brown32cbc38552011-12-01 14:01:49 -0800110
Jeff Brown072ec962012-02-07 14:46:57 -0800111 status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
112 if (status) {
113 ALOGW("Failed to send finished signal on channel '%s'. status=%d",
114 getInputChannelName(), status);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800115 }
Jeff Brown072ec962012-02-07 14:46:57 -0800116 return status;
Jeff Brown32cbc38552011-12-01 14:01:49 -0800117}
118
Jeff Brown80a1de12012-05-31 16:23:11 -0700119int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800120 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
Steve Block3762c312012-01-06 19:20:56 +0000121 ALOGE("channel '%s' ~ Publisher closed input channel or an error occurred. "
Jeff Brown80a1de12012-05-31 16:23:11 -0700122 "events=0x%x", getInputChannelName(), events);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800123 return 0; // remove the callback
124 }
125
126 if (!(events & ALOOPER_EVENT_INPUT)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000127 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
Jeff Brown80a1de12012-05-31 16:23:11 -0700128 "events=0x%x", getInputChannelName(), events);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800129 return 1;
130 }
131
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700132 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jeff Brown80a1de12012-05-31 16:23:11 -0700133 status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
134 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
Jeff Brown072ec962012-02-07 14:46:57 -0800135 return status == OK || status == NO_MEMORY ? 1 : 0;
136}
Jeff Brown32cbc38552011-12-01 14:01:49 -0800137
Jeff Brown771526c2012-04-27 15:13:25 -0700138status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
139 bool consumeBatches, nsecs_t frameTime) {
Jeff Brown072ec962012-02-07 14:46:57 -0800140#if DEBUG_DISPATCH_CYCLE
Jeff Brown771526c2012-04-27 15:13:25 -0700141 ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
142 getInputChannelName(), consumeBatches ? "true" : "false", frameTime);
Jeff Brown072ec962012-02-07 14:46:57 -0800143#endif
144
145 if (consumeBatches) {
146 mBatchedInputEventPending = false;
Jeff Brown32cbc38552011-12-01 14:01:49 -0800147 }
148
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700149 bool skipCallbacks = false;
Jeff Brown072ec962012-02-07 14:46:57 -0800150 for (;;) {
151 uint32_t seq;
152 InputEvent* inputEvent;
153 status_t status = mInputConsumer.consume(&mInputEventFactory,
Jeff Brown771526c2012-04-27 15:13:25 -0700154 consumeBatches, frameTime, &seq, &inputEvent);
Jeff Brown072ec962012-02-07 14:46:57 -0800155 if (status) {
156 if (status == WOULD_BLOCK) {
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700157 if (!skipCallbacks && !mBatchedInputEventPending
158 && mInputConsumer.hasPendingBatch()) {
Jeff Brown072ec962012-02-07 14:46:57 -0800159 // There is a pending batch. Come back later.
160 mBatchedInputEventPending = true;
Jeff Brown32cbc38552011-12-01 14:01:49 -0800161#if DEBUG_DISPATCH_CYCLE
Jeff Brown072ec962012-02-07 14:46:57 -0800162 ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
163 getInputChannelName());
Jeff Brown32cbc38552011-12-01 14:01:49 -0800164#endif
Jeff Brown072ec962012-02-07 14:46:57 -0800165 env->CallVoidMethod(mReceiverObjGlobal,
166 gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700167 if (env->ExceptionCheck()) {
168 ALOGE("Exception dispatching batched input events.");
Jeff Brown072ec962012-02-07 14:46:57 -0800169 mBatchedInputEventPending = false; // try again later
170 }
171 }
172 return OK;
173 }
174 ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
175 getInputChannelName(), status);
176 return status;
177 }
178 assert(inputEvent);
179
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700180 if (!skipCallbacks) {
181 jobject inputEventObj;
182 switch (inputEvent->getType()) {
183 case AINPUT_EVENT_TYPE_KEY:
Jeff Brown32cbc38552011-12-01 14:01:49 -0800184#if DEBUG_DISPATCH_CYCLE
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700185 ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
Jeff Brown32cbc38552011-12-01 14:01:49 -0800186#endif
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700187 inputEventObj = android_view_KeyEvent_fromNative(env,
188 static_cast<KeyEvent*>(inputEvent));
189 break;
Jeff Brown32cbc38552011-12-01 14:01:49 -0800190
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700191 case AINPUT_EVENT_TYPE_MOTION:
Jeff Brown072ec962012-02-07 14:46:57 -0800192#if DEBUG_DISPATCH_CYCLE
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700193 ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
Jeff Brown072ec962012-02-07 14:46:57 -0800194#endif
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700195 inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
196 static_cast<MotionEvent*>(inputEvent));
197 break;
Jeff Brown32cbc38552011-12-01 14:01:49 -0800198
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700199 default:
200 assert(false); // InputConsumer should prevent this from ever happening
201 inputEventObj = NULL;
202 }
203
204 if (inputEventObj) {
205#if DEBUG_DISPATCH_CYCLE
206 ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
207#endif
208 env->CallVoidMethod(mReceiverObjGlobal,
209 gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
210 if (env->ExceptionCheck()) {
211 ALOGE("Exception dispatching input event.");
212 skipCallbacks = true;
213 }
214 } else {
215 ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
216 skipCallbacks = true;
217 }
Jeff Brown072ec962012-02-07 14:46:57 -0800218 }
Jeff Brown32cbc38552011-12-01 14:01:49 -0800219
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700220 if (skipCallbacks) {
Jeff Brown072ec962012-02-07 14:46:57 -0800221 mInputConsumer.sendFinishedSignal(seq, false);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800222 }
223 }
Jeff Brown32cbc38552011-12-01 14:01:49 -0800224}
225
226
227static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
228 jobject inputChannelObj, jobject messageQueueObj) {
229 sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
230 inputChannelObj);
231 if (inputChannel == NULL) {
232 jniThrowRuntimeException(env, "InputChannel is not initialized.");
233 return 0;
234 }
235
Jeff Brown603b4452012-04-06 17:39:41 -0700236 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
237 if (messageQueue == NULL) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800238 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
239 return 0;
240 }
241
242 sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
Jeff Brown603b4452012-04-06 17:39:41 -0700243 receiverObj, inputChannel, messageQueue);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800244 status_t status = receiver->initialize();
245 if (status) {
246 String8 message;
247 message.appendFormat("Failed to initialize input event receiver. status=%d", status);
248 jniThrowRuntimeException(env, message.string());
249 return 0;
250 }
251
252 receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
253 return reinterpret_cast<jint>(receiver.get());
254}
255
256static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
257 sp<NativeInputEventReceiver> receiver =
258 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
Jeff Brown80a1de12012-05-31 16:23:11 -0700259 receiver->dispose();
Jeff Brown32cbc38552011-12-01 14:01:49 -0800260 receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
261}
262
Jeff Brown072ec962012-02-07 14:46:57 -0800263static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
264 jint seq, jboolean handled) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800265 sp<NativeInputEventReceiver> receiver =
266 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
Jeff Brown072ec962012-02-07 14:46:57 -0800267 status_t status = receiver->finishInputEvent(seq, handled);
Jeff Brown9806a232012-02-17 10:28:09 -0800268 if (status && status != DEAD_OBJECT) {
Jeff Brown32cbc38552011-12-01 14:01:49 -0800269 String8 message;
270 message.appendFormat("Failed to finish input event. status=%d", status);
271 jniThrowRuntimeException(env, message.string());
272 }
273}
274
Jeff Brown771526c2012-04-27 15:13:25 -0700275static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr,
276 jlong frameTimeNanos) {
Jeff Brown072ec962012-02-07 14:46:57 -0800277 sp<NativeInputEventReceiver> receiver =
278 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
Jeff Brown771526c2012-04-27 15:13:25 -0700279 status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos);
Jeff Brown3bdcdd82012-04-10 20:36:07 -0700280 if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
Jeff Brown072ec962012-02-07 14:46:57 -0800281 String8 message;
282 message.appendFormat("Failed to consume batched input event. status=%d", status);
283 jniThrowRuntimeException(env, message.string());
284 }
285}
286
Jeff Brown32cbc38552011-12-01 14:01:49 -0800287
288static JNINativeMethod gMethods[] = {
289 /* name, signature, funcPtr */
290 { "nativeInit",
291 "(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
292 (void*)nativeInit },
Jeff Brown072ec962012-02-07 14:46:57 -0800293 { "nativeDispose", "(I)V",
Jeff Brown32cbc38552011-12-01 14:01:49 -0800294 (void*)nativeDispose },
Jeff Brown072ec962012-02-07 14:46:57 -0800295 { "nativeFinishInputEvent", "(IIZ)V",
296 (void*)nativeFinishInputEvent },
Jeff Brown771526c2012-04-27 15:13:25 -0700297 { "nativeConsumeBatchedInputEvents", "(IJ)V",
Jeff Brown072ec962012-02-07 14:46:57 -0800298 (void*)nativeConsumeBatchedInputEvents },
Jeff Brown32cbc38552011-12-01 14:01:49 -0800299};
300
301#define FIND_CLASS(var, className) \
302 var = env->FindClass(className); \
303 LOG_FATAL_IF(! var, "Unable to find class " className); \
304 var = jclass(env->NewGlobalRef(var));
305
306#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
307 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
308 LOG_FATAL_IF(! var, "Unable to find method " methodName);
309
310int register_android_view_InputEventReceiver(JNIEnv* env) {
311 int res = jniRegisterNativeMethods(env, "android/view/InputEventReceiver",
312 gMethods, NELEM(gMethods));
313 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
314
315 FIND_CLASS(gInputEventReceiverClassInfo.clazz, "android/view/InputEventReceiver");
316
317 GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
318 gInputEventReceiverClassInfo.clazz,
Jeff Brown072ec962012-02-07 14:46:57 -0800319 "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
320 GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
321 gInputEventReceiverClassInfo.clazz,
322 "dispatchBatchedInputEventPending", "()V");
Jeff Brown32cbc38552011-12-01 14:01:49 -0800323 return 0;
324}
325
326} // namespace android