1 /* 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 #include <inttypes.h> 22 23 #include <nativehelper/JNIHelp.h> 24 25 #include <android-base/stringprintf.h> 26 #include <android_runtime/AndroidRuntime.h> 27 #include <input/InputTransport.h> 28 #include <log/log.h> 29 #include <utils/Looper.h> 30 #include <variant> 31 #include <vector> 32 #include "android_os_MessageQueue.h" 33 #include "android_view_InputChannel.h" 34 #include "android_view_KeyEvent.h" 35 #include "android_view_MotionEvent.h" 36 37 #include <nativehelper/ScopedLocalRef.h> 38 39 #include "core_jni_helpers.h" 40 41 namespace android { 42 43 static const bool kDebugDispatchCycle = false; 44 45 static const char* toString(bool value) { 46 return value ? "true" : "false"; 47 } 48 49 static struct { 50 jclass clazz; 51 52 jmethodID dispatchInputEvent; 53 jmethodID onFocusEvent; 54 jmethodID onPointerCaptureEvent; 55 jmethodID onDragEvent; 56 jmethodID onBatchedInputEventPending; 57 } gInputEventReceiverClassInfo; 58 59 // Add prefix to the beginning of each line in 'str' 60 static std::string addPrefix(std::string str, std::string_view prefix) { 61 str.insert(0, prefix); // insert at the beginning of the first line 62 const size_t prefixLength = prefix.length(); 63 size_t pos = prefixLength; // just inserted prefix. start at the end of it 64 while (true) { // process all newline characters in 'str' 65 pos = str.find('\n', pos); 66 if (pos == std::string::npos) { 67 break; 68 } 69 str.insert(pos + 1, prefix); // insert prefix just after the '\n' character 70 pos += prefixLength + 1; // advance the position past the newly inserted prefix 71 } 72 return str; 73 } 74 75 class NativeInputEventReceiver : public LooperCallback { 76 public: 77 NativeInputEventReceiver(JNIEnv* env, jobject receiverWeak, 78 const std::shared_ptr<InputChannel>& inputChannel, 79 const sp<MessageQueue>& messageQueue); 80 81 status_t initialize(); 82 void dispose(); 83 status_t finishInputEvent(uint32_t seq, bool handled); 84 status_t reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime); 85 status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, 86 bool* outConsumedBatch); 87 std::string dump(const char* prefix); 88 89 protected: 90 virtual ~NativeInputEventReceiver(); 91 92 private: 93 struct Finish { 94 uint32_t seq; 95 bool handled; 96 }; 97 98 struct Timeline { 99 int32_t inputEventId; 100 std::array<nsecs_t, GraphicsTimeline::SIZE> timeline; 101 }; 102 typedef std::variant<Finish, Timeline> OutboundEvent; 103 104 jobject mReceiverWeakGlobal; 105 InputConsumer mInputConsumer; 106 sp<MessageQueue> mMessageQueue; 107 PreallocatedInputEventFactory mInputEventFactory; 108 bool mBatchedInputEventPending; 109 int mFdEvents; 110 std::vector<OutboundEvent> mOutboundQueue; 111 112 void setFdEvents(int events); 113 114 const std::string getInputChannelName() { 115 return mInputConsumer.getChannel()->getName(); 116 } 117 118 status_t processOutboundEvents(); 119 // From 'LooperCallback' 120 int handleEvent(int receiveFd, int events, void* data) override; 121 }; 122 123 NativeInputEventReceiver::NativeInputEventReceiver( 124 JNIEnv* env, jobject receiverWeak, const std::shared_ptr<InputChannel>& inputChannel, 125 const sp<MessageQueue>& messageQueue) 126 : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), 127 mInputConsumer(inputChannel), 128 mMessageQueue(messageQueue), 129 mBatchedInputEventPending(false), 130 mFdEvents(0) { 131 if (kDebugDispatchCycle) { 132 ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str()); 133 } 134 } 135 136 NativeInputEventReceiver::~NativeInputEventReceiver() { 137 JNIEnv* env = AndroidRuntime::getJNIEnv(); 138 env->DeleteGlobalRef(mReceiverWeakGlobal); 139 } 140 141 status_t NativeInputEventReceiver::initialize() { 142 setFdEvents(ALOOPER_EVENT_INPUT); 143 return OK; 144 } 145 146 void NativeInputEventReceiver::dispose() { 147 if (kDebugDispatchCycle) { 148 ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName().c_str()); 149 } 150 151 setFdEvents(0); 152 } 153 154 status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) { 155 if (kDebugDispatchCycle) { 156 ALOGD("channel '%s' ~ Finished input event.", getInputChannelName().c_str()); 157 } 158 159 Finish finish{ 160 .seq = seq, 161 .handled = handled, 162 }; 163 mOutboundQueue.push_back(finish); 164 return processOutboundEvents(); 165 } 166 167 status_t NativeInputEventReceiver::reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, 168 nsecs_t presentTime) { 169 if (kDebugDispatchCycle) { 170 ALOGD("channel '%s' ~ %s", getInputChannelName().c_str(), __func__); 171 } 172 std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline; 173 graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = gpuCompletedTime; 174 graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime; 175 Timeline timeline{ 176 .inputEventId = inputEventId, 177 .timeline = graphicsTimeline, 178 }; 179 mOutboundQueue.push_back(timeline); 180 return processOutboundEvents(); 181 } 182 183 void NativeInputEventReceiver::setFdEvents(int events) { 184 if (mFdEvents != events) { 185 mFdEvents = events; 186 int fd = mInputConsumer.getChannel()->getFd(); 187 if (events) { 188 mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr); 189 } else { 190 mMessageQueue->getLooper()->removeFd(fd); 191 } 192 } 193 } 194 195 /** 196 * Receiver's primary role is to receive input events, but it has an additional duty of sending 197 * 'ack' for events (using the call 'finishInputEvent') and reporting input event timeline. 198 * 199 * If we are looking at the communication between InputPublisher and InputConsumer, we can say that 200 * from the InputConsumer's perspective, InputMessage's that are sent from publisher to consumer are 201 * called 'inbound / incoming' events, and the InputMessage's sent from InputConsumer to 202 * InputPublisher are 'outbound / outgoing' events. 203 * 204 * NativeInputEventReceiver owns (and acts like) an InputConsumer. So the finish events are outbound 205 * from InputEventReceiver (and will be sent to the InputPublisher). Likewise, timeline events are 206 * outbound events. 207 * 208 * In this function, send as many events from 'mOutboundQueue' as possible across the socket to the 209 * InputPublisher. If no events are remaining, let the looper know so that it doesn't wake up 210 * unnecessarily. 211 */ 212 status_t NativeInputEventReceiver::processOutboundEvents() { 213 while (!mOutboundQueue.empty()) { 214 OutboundEvent& outbound = *mOutboundQueue.begin(); 215 status_t status; 216 217 if (std::holds_alternative<Finish>(outbound)) { 218 const Finish& finish = std::get<Finish>(outbound); 219 status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled); 220 } else if (std::holds_alternative<Timeline>(outbound)) { 221 const Timeline& timeline = std::get<Timeline>(outbound); 222 status = mInputConsumer.sendTimeline(timeline.inputEventId, timeline.timeline); 223 } else { 224 LOG_ALWAYS_FATAL("Unexpected event type in std::variant"); 225 status = BAD_VALUE; 226 } 227 if (status == OK) { 228 // Successful send. Erase the entry and keep trying to send more 229 mOutboundQueue.erase(mOutboundQueue.begin()); 230 continue; 231 } 232 233 // Publisher is busy, try again later. Keep this entry (do not erase) 234 if (status == WOULD_BLOCK) { 235 if (kDebugDispatchCycle) { 236 ALOGD("channel '%s' ~ Remaining outbound events: %zu.", 237 getInputChannelName().c_str(), mOutboundQueue.size()); 238 } 239 setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT); 240 return WOULD_BLOCK; // try again later 241 } 242 243 // Some other error. Give up 244 ALOGW("Failed to send outbound event on channel '%s'. status=%s(%d)", 245 getInputChannelName().c_str(), statusToString(status).c_str(), status); 246 if (status != DEAD_OBJECT) { 247 JNIEnv* env = AndroidRuntime::getJNIEnv(); 248 std::string message = 249 android::base::StringPrintf("Failed to send outbound event. status=%s(%d)", 250 statusToString(status).c_str(), status); 251 jniThrowRuntimeException(env, message.c_str()); 252 mMessageQueue->raiseAndClearException(env, "finishInputEvent"); 253 } 254 return status; 255 } 256 257 // The queue is now empty. Tell looper there's no more output to expect. 258 setFdEvents(ALOOPER_EVENT_INPUT); 259 return OK; 260 } 261 262 int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { 263 // Allowed return values of this function as documented in LooperCallback::handleEvent 264 constexpr int REMOVE_CALLBACK = 0; 265 constexpr int KEEP_CALLBACK = 1; 266 267 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { 268 // This error typically occurs when the publisher has closed the input channel 269 // as part of removing a window or finishing an IME session, in which case 270 // the consumer will soon be disposed as well. 271 if (kDebugDispatchCycle) { 272 ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. events=0x%x", 273 getInputChannelName().c_str(), events); 274 } 275 return REMOVE_CALLBACK; 276 } 277 278 if (events & ALOOPER_EVENT_INPUT) { 279 JNIEnv* env = AndroidRuntime::getJNIEnv(); 280 status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr); 281 mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); 282 return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK; 283 } 284 285 if (events & ALOOPER_EVENT_OUTPUT) { 286 const status_t status = processOutboundEvents(); 287 if (status == OK || status == WOULD_BLOCK) { 288 return KEEP_CALLBACK; 289 } else { 290 return REMOVE_CALLBACK; 291 } 292 } 293 294 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. events=0x%x", 295 getInputChannelName().c_str(), events); 296 return KEEP_CALLBACK; 297 } 298 299 status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, 300 bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { 301 if (kDebugDispatchCycle) { 302 ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64, 303 getInputChannelName().c_str(), toString(consumeBatches), frameTime); 304 } 305 306 if (consumeBatches) { 307 mBatchedInputEventPending = false; 308 } 309 if (outConsumedBatch) { 310 *outConsumedBatch = false; 311 } 312 313 ScopedLocalRef<jobject> receiverObj(env, nullptr); 314 bool skipCallbacks = false; 315 for (;;) { 316 uint32_t seq; 317 InputEvent* inputEvent; 318 319 status_t status = mInputConsumer.consume(&mInputEventFactory, 320 consumeBatches, frameTime, &seq, &inputEvent); 321 if (status != OK && status != WOULD_BLOCK) { 322 ALOGE("channel '%s' ~ Failed to consume input event. status=%s(%d)", 323 getInputChannelName().c_str(), statusToString(status).c_str(), status); 324 return status; 325 } 326 327 if (status == WOULD_BLOCK) { 328 if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) { 329 // There is a pending batch. Come back later. 330 if (!receiverObj.get()) { 331 receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); 332 if (!receiverObj.get()) { 333 ALOGW("channel '%s' ~ Receiver object was finalized " 334 "without being disposed.", 335 getInputChannelName().c_str()); 336 return DEAD_OBJECT; 337 } 338 } 339 340 mBatchedInputEventPending = true; 341 if (kDebugDispatchCycle) { 342 ALOGD("channel '%s' ~ Dispatching batched input event pending notification.", 343 getInputChannelName().c_str()); 344 } 345 346 env->CallVoidMethod(receiverObj.get(), 347 gInputEventReceiverClassInfo.onBatchedInputEventPending, 348 mInputConsumer.getPendingBatchSource()); 349 if (env->ExceptionCheck()) { 350 ALOGE("Exception dispatching batched input events."); 351 mBatchedInputEventPending = false; // try again later 352 } 353 } 354 return OK; 355 } 356 assert(inputEvent); 357 358 if (!skipCallbacks) { 359 if (!receiverObj.get()) { 360 receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); 361 if (!receiverObj.get()) { 362 ALOGW("channel '%s' ~ Receiver object was finalized " 363 "without being disposed.", getInputChannelName().c_str()); 364 return DEAD_OBJECT; 365 } 366 } 367 368 jobject inputEventObj; 369 switch (inputEvent->getType()) { 370 case AINPUT_EVENT_TYPE_KEY: 371 if (kDebugDispatchCycle) { 372 ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str()); 373 } 374 inputEventObj = android_view_KeyEvent_fromNative(env, 375 static_cast<KeyEvent*>(inputEvent)); 376 break; 377 378 case AINPUT_EVENT_TYPE_MOTION: { 379 if (kDebugDispatchCycle) { 380 ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str()); 381 } 382 MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent); 383 if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) { 384 *outConsumedBatch = true; 385 } 386 inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent); 387 break; 388 } 389 case AINPUT_EVENT_TYPE_FOCUS: { 390 FocusEvent* focusEvent = static_cast<FocusEvent*>(inputEvent); 391 if (kDebugDispatchCycle) { 392 ALOGD("channel '%s' ~ Received focus event: hasFocus=%s, inTouchMode=%s.", 393 getInputChannelName().c_str(), toString(focusEvent->getHasFocus()), 394 toString(focusEvent->getInTouchMode())); 395 } 396 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onFocusEvent, 397 jboolean(focusEvent->getHasFocus()), 398 jboolean(focusEvent->getInTouchMode())); 399 finishInputEvent(seq, true /* handled */); 400 continue; 401 } 402 case AINPUT_EVENT_TYPE_CAPTURE: { 403 const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(inputEvent); 404 if (kDebugDispatchCycle) { 405 ALOGD("channel '%s' ~ Received capture event: pointerCaptureEnabled=%s", 406 getInputChannelName().c_str(), 407 toString(captureEvent->getPointerCaptureEnabled())); 408 } 409 env->CallVoidMethod(receiverObj.get(), 410 gInputEventReceiverClassInfo.onPointerCaptureEvent, 411 jboolean(captureEvent->getPointerCaptureEnabled())); 412 finishInputEvent(seq, true /* handled */); 413 continue; 414 } 415 case AINPUT_EVENT_TYPE_DRAG: { 416 const DragEvent* dragEvent = static_cast<DragEvent*>(inputEvent); 417 if (kDebugDispatchCycle) { 418 ALOGD("channel '%s' ~ Received drag event: isExiting=%s", 419 getInputChannelName().c_str(), toString(dragEvent->isExiting())); 420 } 421 env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onDragEvent, 422 jboolean(dragEvent->isExiting()), dragEvent->getX(), 423 dragEvent->getY()); 424 finishInputEvent(seq, true /* handled */); 425 continue; 426 } 427 428 default: 429 assert(false); // InputConsumer should prevent this from ever happening 430 inputEventObj = nullptr; 431 } 432 433 if (inputEventObj) { 434 if (kDebugDispatchCycle) { 435 ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str()); 436 } 437 env->CallVoidMethod(receiverObj.get(), 438 gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); 439 if (env->ExceptionCheck()) { 440 ALOGE("Exception dispatching input event."); 441 skipCallbacks = true; 442 } 443 env->DeleteLocalRef(inputEventObj); 444 } else { 445 ALOGW("channel '%s' ~ Failed to obtain event object.", 446 getInputChannelName().c_str()); 447 skipCallbacks = true; 448 } 449 } 450 451 if (skipCallbacks) { 452 mInputConsumer.sendFinishedSignal(seq, false); 453 } 454 } 455 } 456 457 std::string NativeInputEventReceiver::dump(const char* prefix) { 458 std::string out; 459 std::string consumerDump = addPrefix(mInputConsumer.dump(), " "); 460 out = out + "mInputConsumer:\n" + consumerDump + "\n"; 461 462 out += android::base::StringPrintf("mBatchedInputEventPending: %s\n", 463 toString(mBatchedInputEventPending)); 464 out = out + "mOutboundQueue:\n"; 465 for (const OutboundEvent& outbound : mOutboundQueue) { 466 if (std::holds_alternative<Finish>(outbound)) { 467 const Finish& finish = std::get<Finish>(outbound); 468 out += android::base::StringPrintf(" Finish: seq=%" PRIu32 " handled=%s\n", finish.seq, 469 toString(finish.handled)); 470 } else if (std::holds_alternative<Timeline>(outbound)) { 471 const Timeline& timeline = std::get<Timeline>(outbound); 472 out += android::base:: 473 StringPrintf(" Timeline: inputEventId=%" PRId32 " gpuCompletedTime=%" PRId64 474 ", presentTime=%" PRId64 "\n", 475 timeline.inputEventId, 476 timeline.timeline[GraphicsTimeline::GPU_COMPLETED_TIME], 477 timeline.timeline[GraphicsTimeline::PRESENT_TIME]); 478 } 479 } 480 if (mOutboundQueue.empty()) { 481 out = out + " <empty>\n"; 482 } 483 return addPrefix(out, prefix); 484 } 485 486 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, 487 jobject inputChannelObj, jobject messageQueueObj) { 488 std::shared_ptr<InputChannel> inputChannel = 489 android_view_InputChannel_getInputChannel(env, inputChannelObj); 490 if (inputChannel == nullptr) { 491 jniThrowRuntimeException(env, "InputChannel is not initialized."); 492 return 0; 493 } 494 495 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 496 if (messageQueue == nullptr) { 497 jniThrowRuntimeException(env, "MessageQueue is not initialized."); 498 return 0; 499 } 500 501 sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, 502 receiverWeak, inputChannel, messageQueue); 503 status_t status = receiver->initialize(); 504 if (status) { 505 std::string message = android::base:: 506 StringPrintf("Failed to initialize input event receiver. status=%s(%d)", 507 statusToString(status).c_str(), status); 508 jniThrowRuntimeException(env, message.c_str()); 509 return 0; 510 } 511 512 receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object 513 return reinterpret_cast<jlong>(receiver.get()); 514 } 515 516 static void nativeDispose(JNIEnv* env, jclass clazz, jlong receiverPtr) { 517 sp<NativeInputEventReceiver> receiver = 518 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); 519 receiver->dispose(); 520 receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object 521 } 522 523 static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr, 524 jint seq, jboolean handled) { 525 sp<NativeInputEventReceiver> receiver = 526 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); 527 status_t status = receiver->finishInputEvent(seq, handled); 528 if (status == OK || status == WOULD_BLOCK) { 529 return; // normal operation 530 } 531 if (status != DEAD_OBJECT) { 532 std::string message = 533 android::base::StringPrintf("Failed to finish input event. status=%s(%d)", 534 statusToString(status).c_str(), status); 535 jniThrowRuntimeException(env, message.c_str()); 536 } 537 } 538 539 static void nativeReportTimeline(JNIEnv* env, jclass clazz, jlong receiverPtr, jint inputEventId, 540 jlong gpuCompletedTime, jlong presentTime) { 541 if (IdGenerator::getSource(inputEventId) != IdGenerator::Source::INPUT_READER) { 542 // skip this event, it did not originate from hardware 543 return; 544 } 545 sp<NativeInputEventReceiver> receiver = 546 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); 547 status_t status = receiver->reportTimeline(inputEventId, gpuCompletedTime, presentTime); 548 if (status == OK || status == WOULD_BLOCK) { 549 return; // normal operation 550 } 551 if (status != DEAD_OBJECT) { 552 std::string message = android::base::StringPrintf("Failed to send timeline. status=%s(%d)", 553 strerror(-status), status); 554 jniThrowRuntimeException(env, message.c_str()); 555 } 556 } 557 558 static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong receiverPtr, 559 jlong frameTimeNanos) { 560 sp<NativeInputEventReceiver> receiver = 561 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); 562 bool consumedBatch; 563 status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos, 564 &consumedBatch); 565 if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) { 566 std::string message = 567 android::base::StringPrintf("Failed to consume batched input event. status=%s(%d)", 568 statusToString(status).c_str(), status); 569 jniThrowRuntimeException(env, message.c_str()); 570 return JNI_FALSE; 571 } 572 return consumedBatch ? JNI_TRUE : JNI_FALSE; 573 } 574 575 static jstring nativeDump(JNIEnv* env, jclass clazz, jlong receiverPtr, jstring prefix) { 576 sp<NativeInputEventReceiver> receiver = 577 reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); 578 ScopedUtfChars prefixChars(env, prefix); 579 return env->NewStringUTF(receiver->dump(prefixChars.c_str()).c_str()); 580 } 581 582 static const JNINativeMethod gMethods[] = { 583 /* name, signature, funcPtr */ 584 {"nativeInit", 585 "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", 586 (void*)nativeInit}, 587 {"nativeDispose", "(J)V", (void*)nativeDispose}, 588 {"nativeFinishInputEvent", "(JIZ)V", (void*)nativeFinishInputEvent}, 589 {"nativeReportTimeline", "(JIJJ)V", (void*)nativeReportTimeline}, 590 {"nativeConsumeBatchedInputEvents", "(JJ)Z", (void*)nativeConsumeBatchedInputEvents}, 591 {"nativeDump", "(JLjava/lang/String;)Ljava/lang/String;", (void*)nativeDump}, 592 }; 593 594 int register_android_view_InputEventReceiver(JNIEnv* env) { 595 int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver", 596 gMethods, NELEM(gMethods)); 597 598 jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver"); 599 gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); 600 601 gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env, 602 gInputEventReceiverClassInfo.clazz, 603 "dispatchInputEvent", "(ILandroid/view/InputEvent;)V"); 604 gInputEventReceiverClassInfo.onFocusEvent = 605 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onFocusEvent", "(ZZ)V"); 606 gInputEventReceiverClassInfo.onPointerCaptureEvent = 607 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onPointerCaptureEvent", 608 "(Z)V"); 609 gInputEventReceiverClassInfo.onDragEvent = 610 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onDragEvent", "(ZFF)V"); 611 gInputEventReceiverClassInfo.onBatchedInputEventPending = 612 GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "onBatchedInputEventPending", 613 "(I)V"); 614 615 return res; 616 } 617 618 } // namespace android 619