android_app_NativeActivity.cpp revision 08d5b8fad8d46ccb64db2fdcb4d66972ec87bf48
1/* 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 "NativeActivity" 18#include <utils/Log.h> 19 20#include <poll.h> 21#include <dlfcn.h> 22#include <fcntl.h> 23 24#include <android_runtime/AndroidRuntime.h> 25#include <android_runtime/android_view_Surface.h> 26#include <android_runtime/android_app_NativeActivity.h> 27#include <android_runtime/android_util_AssetManager.h> 28#include <surfaceflinger/Surface.h> 29#include <ui/egl/android_natives.h> 30#include <ui/InputTransport.h> 31#include <utils/PollLoop.h> 32 33#include "JNIHelp.h" 34#include "android_os_MessageQueue.h" 35#include "android_view_InputChannel.h" 36#include "android_view_KeyEvent.h" 37 38//#define LOG_TRACE(...) 39#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) 40 41namespace android 42{ 43 44static struct { 45 jclass clazz; 46 47 jmethodID dispatchUnhandledKeyEvent; 48 jmethodID preDispatchKeyEvent; 49 jmethodID setWindowFlags; 50 jmethodID setWindowFormat; 51 jmethodID showIme; 52 jmethodID hideIme; 53} gNativeActivityClassInfo; 54 55// ------------------------------------------------------------------------ 56 57struct ActivityWork { 58 int32_t cmd; 59 int32_t arg1; 60 int32_t arg2; 61}; 62 63enum { 64 CMD_DEF_KEY = 1, 65 CMD_SET_WINDOW_FORMAT, 66 CMD_SET_WINDOW_FLAGS, 67 CMD_SHOW_SOFT_INPUT, 68 CMD_HIDE_SOFT_INPUT, 69}; 70 71static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) { 72 ActivityWork work; 73 work.cmd = cmd; 74 work.arg1 = arg1; 75 work.arg2 = arg2; 76 77 LOG_TRACE("write_work: cmd=%d", cmd); 78 79restart: 80 int res = write(fd, &work, sizeof(work)); 81 if (res < 0 && errno == EINTR) { 82 goto restart; 83 } 84 85 if (res == sizeof(work)) return; 86 87 if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno)); 88 else LOGW("Truncated writing to work fd: %d", res); 89} 90 91static bool read_work(int fd, ActivityWork* outWork) { 92 int res = read(fd, outWork, sizeof(ActivityWork)); 93 // no need to worry about EINTR, poll loop will just come back again. 94 if (res == sizeof(ActivityWork)) return true; 95 96 if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno)); 97 else LOGW("Truncated reading work fd: %d", res); 98 return false; 99} 100 101// ------------------------------------------------------------------------ 102 103} // namespace android 104 105using namespace android; 106 107AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) : 108 mWorkWrite(workWrite), mConsumer(channel), mSeq(0) { 109 int msgpipe[2]; 110 if (pipe(msgpipe)) { 111 LOGW("could not create pipe: %s", strerror(errno)); 112 mDispatchKeyRead = mDispatchKeyWrite = -1; 113 } else { 114 mDispatchKeyRead = msgpipe[0]; 115 mDispatchKeyWrite = msgpipe[1]; 116 int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK); 117 SLOGW_IF(result != 0, "Could not make AInputQueue read pipe " 118 "non-blocking: %s", strerror(errno)); 119 result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK); 120 SLOGW_IF(result != 0, "Could not make AInputQueue write pipe " 121 "non-blocking: %s", strerror(errno)); 122 } 123} 124 125AInputQueue::~AInputQueue() { 126 close(mDispatchKeyRead); 127 close(mDispatchKeyWrite); 128} 129 130void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) { 131 mPollLoop = static_cast<android::PollLoop*>(looper); 132 mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(), 133 POLLIN, callback, data); 134 mPollLoop->setLooperCallback(mDispatchKeyRead, 135 POLLIN, callback, data); 136} 137 138void AInputQueue::detachLooper() { 139 mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd()); 140 mPollLoop->removeCallback(mDispatchKeyRead); 141} 142 143int32_t AInputQueue::hasEvents() { 144 struct pollfd pfd[2]; 145 146 pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd(); 147 pfd[0].events = POLLIN; 148 pfd[0].revents = 0; 149 pfd[1].fd = mDispatchKeyRead; 150 pfd[0].events = POLLIN; 151 pfd[0].revents = 0; 152 153 int nfd = poll(pfd, 2, 0); 154 if (nfd <= 0) return 0; 155 return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1; 156} 157 158int32_t AInputQueue::getEvent(AInputEvent** outEvent) { 159 *outEvent = NULL; 160 161 bool finishNow = false; 162 163 char byteread; 164 ssize_t nRead = read(mDispatchKeyRead, &byteread, 1); 165 if (nRead == 1) { 166 mLock.lock(); 167 if (mDispatchingKeys.size() > 0) { 168 KeyEvent* kevent = mDispatchingKeys[0]; 169 *outEvent = kevent; 170 mDispatchingKeys.removeAt(0); 171 in_flight_event inflight; 172 inflight.event = kevent; 173 inflight.seq = -1; 174 inflight.doFinish = false; 175 mInFlightEvents.push(inflight); 176 } 177 if (mFinishPreDispatches.size() > 0) { 178 finish_pre_dispatch finish(mFinishPreDispatches[0]); 179 mFinishPreDispatches.removeAt(0); 180 const size_t N = mInFlightEvents.size(); 181 for (size_t i=0; i<N; i++) { 182 const in_flight_event& inflight(mInFlightEvents[i]); 183 if (inflight.seq == finish.seq) { 184 *outEvent = inflight.event; 185 finishNow = finish.handled; 186 } 187 } 188 if (*outEvent == NULL) { 189 LOGW("getEvent couldn't find inflight for seq %d", finish.seq); 190 } 191 } 192 mLock.unlock(); 193 194 if (finishNow) { 195 finishEvent(*outEvent, true); 196 *outEvent = NULL; 197 return -1; 198 } else if (*outEvent != NULL) { 199 return 0; 200 } 201 } 202 203 int32_t res = mConsumer.receiveDispatchSignal(); 204 if (res != android::OK) { 205 LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", 206 mConsumer.getChannel()->getName().string(), res); 207 return -1; 208 } 209 210 InputEvent* myEvent = NULL; 211 res = mConsumer.consume(this, &myEvent); 212 if (res != android::OK) { 213 LOGW("channel '%s' ~ Failed to consume input event. status=%d", 214 mConsumer.getChannel()->getName().string(), res); 215 mConsumer.sendFinishedSignal(); 216 return -1; 217 } 218 219 in_flight_event inflight; 220 inflight.event = myEvent; 221 inflight.seq = -1; 222 inflight.doFinish = true; 223 mInFlightEvents.push(inflight); 224 225 *outEvent = myEvent; 226 return 0; 227} 228 229bool AInputQueue::preDispatchEvent(AInputEvent* event) { 230 if (((InputEvent*)event)->getType() != AINPUT_EVENT_TYPE_KEY) { 231 // The IME only cares about key events. 232 return false; 233 } 234 235 // For now we only send system keys to the IME... this avoids having 236 // critical keys like DPAD go through this path. We really need to have 237 // the IME report which keys it wants. 238 if (!((KeyEvent*)event)->isSystemKey()) { 239 return false; 240 } 241 242 return preDispatchKey((KeyEvent*)event); 243} 244 245void AInputQueue::finishEvent(AInputEvent* event, bool handled) { 246 LOG_TRACE("finishEvent: %p handled=%d", event, handled ? 1 : 0); 247 248 if (!handled && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY 249 && ((KeyEvent*)event)->hasDefaultAction()) { 250 // The app didn't handle this, but it may have a default action 251 // associated with it. We need to hand this back to Java to be 252 // executed. 253 doUnhandledKey((KeyEvent*)event); 254 return; 255 } 256 257 mLock.lock(); 258 const size_t N = mInFlightEvents.size(); 259 for (size_t i=0; i<N; i++) { 260 const in_flight_event& inflight(mInFlightEvents[i]); 261 if (inflight.event == event) { 262 if (inflight.doFinish) { 263 int32_t res = mConsumer.sendFinishedSignal(); 264 if (res != android::OK) { 265 LOGW("Failed to send finished signal on channel '%s'. status=%d", 266 mConsumer.getChannel()->getName().string(), res); 267 } 268 } 269 if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) { 270 mAvailKeyEvents.push(static_cast<KeyEvent*>(event)); 271 } else { 272 mAvailMotionEvents.push(static_cast<MotionEvent*>(event)); 273 } 274 mInFlightEvents.removeAt(i); 275 mLock.unlock(); 276 return; 277 } 278 } 279 mLock.unlock(); 280 281 LOGW("finishEvent called for unknown event: %p", event); 282} 283 284void AInputQueue::dispatchEvent(android::KeyEvent* event) { 285 mLock.lock(); 286 LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(), 287 mDispatchKeyWrite); 288 mDispatchingKeys.add(event); 289 wakeupDispatch(); 290 mLock.unlock(); 291} 292 293void AInputQueue::finishPreDispatch(int seq, bool handled) { 294 mLock.lock(); 295 LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0); 296 finish_pre_dispatch finish; 297 finish.seq = seq; 298 finish.handled = handled; 299 mFinishPreDispatches.add(finish); 300 wakeupDispatch(); 301 mLock.unlock(); 302} 303 304KeyEvent* AInputQueue::consumeUnhandledEvent() { 305 KeyEvent* event = NULL; 306 307 mLock.lock(); 308 if (mUnhandledKeys.size() > 0) { 309 event = mUnhandledKeys[0]; 310 mUnhandledKeys.removeAt(0); 311 } 312 mLock.unlock(); 313 314 LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event); 315 316 return event; 317} 318 319KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) { 320 KeyEvent* event = NULL; 321 322 mLock.lock(); 323 if (mPreDispatchingKeys.size() > 0) { 324 const in_flight_event& inflight(mPreDispatchingKeys[0]); 325 event = static_cast<KeyEvent*>(inflight.event); 326 *outSeq = inflight.seq; 327 mPreDispatchingKeys.removeAt(0); 328 } 329 mLock.unlock(); 330 331 LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event); 332 333 return event; 334} 335 336KeyEvent* AInputQueue::createKeyEvent() { 337 mLock.lock(); 338 KeyEvent* event; 339 if (mAvailKeyEvents.size() <= 0) { 340 event = new KeyEvent(); 341 } else { 342 event = mAvailKeyEvents.top(); 343 mAvailKeyEvents.pop(); 344 } 345 mLock.unlock(); 346 return event; 347} 348 349MotionEvent* AInputQueue::createMotionEvent() { 350 mLock.lock(); 351 MotionEvent* event; 352 if (mAvailMotionEvents.size() <= 0) { 353 event = new MotionEvent(); 354 } else { 355 event = mAvailMotionEvents.top(); 356 mAvailMotionEvents.pop(); 357 } 358 mLock.unlock(); 359 return event; 360} 361 362void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) { 363 mLock.lock(); 364 LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite); 365 if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) { 366 write_work(mWorkWrite, CMD_DEF_KEY); 367 } 368 mUnhandledKeys.add(keyEvent); 369 mLock.unlock(); 370} 371 372bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { 373 mLock.lock(); 374 LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite); 375 const size_t N = mInFlightEvents.size(); 376 for (size_t i=0; i<N; i++) { 377 in_flight_event& inflight(mInFlightEvents.editItemAt(i)); 378 if (inflight.event == keyEvent) { 379 if (inflight.seq >= 0) { 380 // This event has already been pre-dispatched! 381 LOG_TRACE("Event already pre-dispatched!"); 382 mLock.unlock(); 383 return false; 384 } 385 mSeq++; 386 if (mSeq < 0) mSeq = 1; 387 inflight.seq = mSeq; 388 389 if (mPreDispatchingKeys.size() <= 0 && mWorkWrite >= 0) { 390 write_work(mWorkWrite, CMD_DEF_KEY); 391 } 392 mPreDispatchingKeys.add(inflight); 393 mLock.unlock(); 394 return true; 395 } 396 } 397 398 LOGW("preDispatchKey called for unknown event: %p", keyEvent); 399 return false; 400} 401 402void AInputQueue::wakeupDispatch() { 403restart: 404 char dummy = 0; 405 int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); 406 if (res < 0 && errno == EINTR) { 407 goto restart; 408 } 409 410 if (res == sizeof(dummy)) return; 411 412 if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno)); 413 else LOGW("Truncated writing to dispatch fd: %d", res); 414} 415 416namespace android { 417 418// ------------------------------------------------------------------------ 419 420/* 421 * Native state for interacting with the NativeActivity class. 422 */ 423struct NativeCode : public ANativeActivity { 424 NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { 425 memset((ANativeActivity*)this, 0, sizeof(ANativeActivity)); 426 memset(&callbacks, 0, sizeof(callbacks)); 427 dlhandle = _dlhandle; 428 createActivityFunc = _createFunc; 429 nativeWindow = NULL; 430 inputChannel = NULL; 431 nativeInputQueue = NULL; 432 mainWorkRead = mainWorkWrite = -1; 433 } 434 435 ~NativeCode() { 436 if (callbacks.onDestroy != NULL) { 437 callbacks.onDestroy(this); 438 } 439 if (env != NULL && clazz != NULL) { 440 env->DeleteGlobalRef(clazz); 441 } 442 if (pollLoop != NULL && mainWorkRead >= 0) { 443 pollLoop->removeCallback(mainWorkRead); 444 } 445 if (nativeInputQueue != NULL) { 446 nativeInputQueue->mWorkWrite = -1; 447 } 448 setSurface(NULL); 449 setInputChannel(NULL); 450 if (mainWorkRead >= 0) close(mainWorkRead); 451 if (mainWorkWrite >= 0) close(mainWorkWrite); 452 if (dlhandle != NULL) { 453 // for now don't unload... we probably should clean this 454 // up and only keep one open dlhandle per proc, since there 455 // is really no benefit to unloading the code. 456 //dlclose(dlhandle); 457 } 458 } 459 460 void setSurface(jobject _surface) { 461 if (_surface != NULL) { 462 nativeWindow = android_Surface_getNativeWindow(env, _surface); 463 } else { 464 nativeWindow = NULL; 465 } 466 } 467 468 status_t setInputChannel(jobject _channel) { 469 if (inputChannel != NULL) { 470 delete nativeInputQueue; 471 env->DeleteGlobalRef(inputChannel); 472 } 473 inputChannel = NULL; 474 nativeInputQueue = NULL; 475 if (_channel != NULL) { 476 inputChannel = env->NewGlobalRef(_channel); 477 sp<InputChannel> ic = 478 android_view_InputChannel_getInputChannel(env, _channel); 479 if (ic != NULL) { 480 nativeInputQueue = new AInputQueue(ic, mainWorkWrite); 481 if (nativeInputQueue->getConsumer().initialize() != android::OK) { 482 delete nativeInputQueue; 483 nativeInputQueue = NULL; 484 return UNKNOWN_ERROR; 485 } 486 } else { 487 return UNKNOWN_ERROR; 488 } 489 } 490 return OK; 491 } 492 493 ANativeActivityCallbacks callbacks; 494 495 void* dlhandle; 496 ANativeActivity_createFunc* createActivityFunc; 497 498 String8 internalDataPath; 499 String8 externalDataPath; 500 501 sp<ANativeWindow> nativeWindow; 502 int32_t lastWindowWidth; 503 int32_t lastWindowHeight; 504 505 jobject inputChannel; 506 struct AInputQueue* nativeInputQueue; 507 508 // These are used to wake up the main thread to process work. 509 int mainWorkRead; 510 int mainWorkWrite; 511 sp<PollLoop> pollLoop; 512}; 513 514void android_NativeActivity_setWindowFormat( 515 ANativeActivity* activity, int32_t format) { 516 NativeCode* code = static_cast<NativeCode*>(activity); 517 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format); 518} 519 520void android_NativeActivity_setWindowFlags( 521 ANativeActivity* activity, int32_t values, int32_t mask) { 522 NativeCode* code = static_cast<NativeCode*>(activity); 523 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask); 524} 525 526void android_NativeActivity_showSoftInput( 527 ANativeActivity* activity, int32_t flags) { 528 NativeCode* code = static_cast<NativeCode*>(activity); 529 write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags); 530} 531 532void android_NativeActivity_hideSoftInput( 533 ANativeActivity* activity, int32_t flags) { 534 NativeCode* code = static_cast<NativeCode*>(activity); 535 write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags); 536} 537 538// ------------------------------------------------------------------------ 539 540/* 541 * Callback for handling native events on the application's main thread. 542 */ 543static bool mainWorkCallback(int fd, int events, void* data) { 544 NativeCode* code = (NativeCode*)data; 545 if ((events & POLLIN) == 0) { 546 return true; 547 } 548 549 ActivityWork work; 550 if (!read_work(code->mainWorkRead, &work)) { 551 return true; 552 } 553 554 LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd); 555 556 switch (work.cmd) { 557 case CMD_DEF_KEY: { 558 KeyEvent* keyEvent; 559 while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) { 560 jobject inputEventObj = android_view_KeyEvent_fromNative( 561 code->env, keyEvent); 562 code->env->CallVoidMethod(code->clazz, 563 gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj); 564 code->nativeInputQueue->finishEvent(keyEvent, true); 565 } 566 int seq; 567 while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) { 568 jobject inputEventObj = android_view_KeyEvent_fromNative( 569 code->env, keyEvent); 570 code->env->CallVoidMethod(code->clazz, 571 gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq); 572 } 573 } break; 574 case CMD_SET_WINDOW_FORMAT: { 575 code->env->CallVoidMethod(code->clazz, 576 gNativeActivityClassInfo.setWindowFormat, work.arg1); 577 } break; 578 case CMD_SET_WINDOW_FLAGS: { 579 code->env->CallVoidMethod(code->clazz, 580 gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2); 581 } break; 582 case CMD_SHOW_SOFT_INPUT: { 583 code->env->CallVoidMethod(code->clazz, 584 gNativeActivityClassInfo.showIme, work.arg1); 585 } break; 586 case CMD_HIDE_SOFT_INPUT: { 587 code->env->CallVoidMethod(code->clazz, 588 gNativeActivityClassInfo.hideIme, work.arg1); 589 } break; 590 default: 591 LOGW("Unknown work command: %d", work.cmd); 592 break; 593 } 594 595 return true; 596} 597 598// ------------------------------------------------------------------------ 599 600static jint 601loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue, 602 jstring internalDataDir, jstring externalDataDir, int sdkVersion, 603 jobject jAssetMgr, jbyteArray savedState) 604{ 605 LOG_TRACE("loadNativeCode_native"); 606 607 const char* pathStr = env->GetStringUTFChars(path, NULL); 608 NativeCode* code = NULL; 609 610 void* handle = dlopen(pathStr, RTLD_LAZY); 611 612 env->ReleaseStringUTFChars(path, pathStr); 613 614 if (handle != NULL) { 615 code = new NativeCode(handle, (ANativeActivity_createFunc*) 616 dlsym(handle, "ANativeActivity_onCreate")); 617 if (code->createActivityFunc == NULL) { 618 LOGW("ANativeActivity_onCreate not found"); 619 delete code; 620 return 0; 621 } 622 623 code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue); 624 if (code->pollLoop == NULL) { 625 LOGW("Unable to retrieve MessageQueue's PollLoop"); 626 delete code; 627 return 0; 628 } 629 630 int msgpipe[2]; 631 if (pipe(msgpipe)) { 632 LOGW("could not create pipe: %s", strerror(errno)); 633 delete code; 634 return 0; 635 } 636 code->mainWorkRead = msgpipe[0]; 637 code->mainWorkWrite = msgpipe[1]; 638 int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); 639 SLOGW_IF(result != 0, "Could not make main work read pipe " 640 "non-blocking: %s", strerror(errno)); 641 result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); 642 SLOGW_IF(result != 0, "Could not make main work write pipe " 643 "non-blocking: %s", strerror(errno)); 644 code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code); 645 646 code->ANativeActivity::callbacks = &code->callbacks; 647 if (env->GetJavaVM(&code->vm) < 0) { 648 LOGW("NativeActivity GetJavaVM failed"); 649 delete code; 650 return 0; 651 } 652 code->env = env; 653 code->clazz = env->NewGlobalRef(clazz); 654 655 const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL); 656 code->internalDataPath = dirStr; 657 code->internalDataPath = code->internalDataPath.string(); 658 env->ReleaseStringUTFChars(path, dirStr); 659 660 dirStr = env->GetStringUTFChars(externalDataDir, NULL); 661 code->externalDataPath = dirStr; 662 code->externalDataPath = code->externalDataPath.string(); 663 env->ReleaseStringUTFChars(path, dirStr); 664 665 code->sdkVersion = sdkVersion; 666 667 code->assetManager = assetManagerForJavaObject(env, jAssetMgr); 668 669 jbyte* rawSavedState = NULL; 670 jsize rawSavedSize = 0; 671 if (savedState != NULL) { 672 rawSavedState = env->GetByteArrayElements(savedState, NULL); 673 rawSavedSize = env->GetArrayLength(savedState); 674 } 675 676 code->createActivityFunc(code, rawSavedState, rawSavedSize); 677 678 if (rawSavedState != NULL) { 679 env->ReleaseByteArrayElements(savedState, rawSavedState, 0); 680 } 681 } 682 683 return (jint)code; 684} 685 686static void 687unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle) 688{ 689 LOG_TRACE("unloadNativeCode_native"); 690 if (handle != 0) { 691 NativeCode* code = (NativeCode*)handle; 692 delete code; 693 } 694} 695 696static void 697onStart_native(JNIEnv* env, jobject clazz, jint handle) 698{ 699 LOG_TRACE("onStart_native"); 700 if (handle != 0) { 701 NativeCode* code = (NativeCode*)handle; 702 if (code->callbacks.onStart != NULL) { 703 code->callbacks.onStart(code); 704 } 705 } 706} 707 708static void 709onResume_native(JNIEnv* env, jobject clazz, jint handle) 710{ 711 LOG_TRACE("onResume_native"); 712 if (handle != 0) { 713 NativeCode* code = (NativeCode*)handle; 714 if (code->callbacks.onResume != NULL) { 715 code->callbacks.onResume(code); 716 } 717 } 718} 719 720static jbyteArray 721onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) 722{ 723 LOG_TRACE("onSaveInstanceState_native"); 724 725 jbyteArray array = NULL; 726 727 if (handle != 0) { 728 NativeCode* code = (NativeCode*)handle; 729 if (code->callbacks.onSaveInstanceState != NULL) { 730 size_t len = 0; 731 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len); 732 if (len > 0) { 733 array = env->NewByteArray(len); 734 if (array != NULL) { 735 env->SetByteArrayRegion(array, 0, len, state); 736 } 737 } 738 if (state != NULL) { 739 free(state); 740 } 741 } 742 } 743 744 return array; 745} 746 747static void 748onPause_native(JNIEnv* env, jobject clazz, jint handle) 749{ 750 LOG_TRACE("onPause_native"); 751 if (handle != 0) { 752 NativeCode* code = (NativeCode*)handle; 753 if (code->callbacks.onPause != NULL) { 754 code->callbacks.onPause(code); 755 } 756 } 757} 758 759static void 760onStop_native(JNIEnv* env, jobject clazz, jint handle) 761{ 762 LOG_TRACE("onStop_native"); 763 if (handle != 0) { 764 NativeCode* code = (NativeCode*)handle; 765 if (code->callbacks.onStop != NULL) { 766 code->callbacks.onStop(code); 767 } 768 } 769} 770 771static void 772onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle) 773{ 774 LOG_TRACE("onConfigurationChanged_native"); 775 if (handle != 0) { 776 NativeCode* code = (NativeCode*)handle; 777 if (code->callbacks.onConfigurationChanged != NULL) { 778 code->callbacks.onConfigurationChanged(code); 779 } 780 } 781} 782 783static void 784onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) 785{ 786 LOG_TRACE("onLowMemory_native"); 787 if (handle != 0) { 788 NativeCode* code = (NativeCode*)handle; 789 if (code->callbacks.onLowMemory != NULL) { 790 code->callbacks.onLowMemory(code); 791 } 792 } 793} 794 795static void 796onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused) 797{ 798 LOG_TRACE("onWindowFocusChanged_native"); 799 if (handle != 0) { 800 NativeCode* code = (NativeCode*)handle; 801 if (code->callbacks.onWindowFocusChanged != NULL) { 802 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); 803 } 804 } 805} 806 807static void 808onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 809{ 810 LOG_TRACE("onSurfaceCreated_native"); 811 if (handle != 0) { 812 NativeCode* code = (NativeCode*)handle; 813 code->setSurface(surface); 814 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) { 815 code->callbacks.onNativeWindowCreated(code, 816 code->nativeWindow.get()); 817 } 818 } 819} 820 821static int32_t getWindowProp(ANativeWindow* window, int what) { 822 int value; 823 int res = window->query(window, what, &value); 824 return res < 0 ? res : value; 825} 826 827static void 828onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface, 829 jint format, jint width, jint height) 830{ 831 LOG_TRACE("onSurfaceChanged_native"); 832 if (handle != 0) { 833 NativeCode* code = (NativeCode*)handle; 834 sp<ANativeWindow> oldNativeWindow = code->nativeWindow; 835 code->setSurface(surface); 836 if (oldNativeWindow != code->nativeWindow) { 837 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 838 code->callbacks.onNativeWindowDestroyed(code, 839 oldNativeWindow.get()); 840 } 841 if (code->nativeWindow != NULL) { 842 if (code->callbacks.onNativeWindowCreated != NULL) { 843 code->callbacks.onNativeWindowCreated(code, 844 code->nativeWindow.get()); 845 } 846 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(), 847 NATIVE_WINDOW_WIDTH); 848 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(), 849 NATIVE_WINDOW_HEIGHT); 850 } 851 } else { 852 // Maybe it resized? 853 int32_t newWidth = getWindowProp(code->nativeWindow.get(), 854 NATIVE_WINDOW_WIDTH); 855 int32_t newHeight = getWindowProp(code->nativeWindow.get(), 856 NATIVE_WINDOW_HEIGHT); 857 if (newWidth != code->lastWindowWidth 858 || newHeight != code->lastWindowHeight) { 859 if (code->callbacks.onNativeWindowResized != NULL) { 860 code->callbacks.onNativeWindowResized(code, 861 code->nativeWindow.get()); 862 } 863 } 864 } 865 } 866} 867 868static void 869onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle) 870{ 871 LOG_TRACE("onSurfaceRedrawNeeded_native"); 872 if (handle != 0) { 873 NativeCode* code = (NativeCode*)handle; 874 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) { 875 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get()); 876 } 877 } 878} 879 880static void 881onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 882{ 883 LOG_TRACE("onSurfaceDestroyed_native"); 884 if (handle != 0) { 885 NativeCode* code = (NativeCode*)handle; 886 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 887 code->callbacks.onNativeWindowDestroyed(code, 888 code->nativeWindow.get()); 889 } 890 code->setSurface(NULL); 891 } 892} 893 894static void 895onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel) 896{ 897 LOG_TRACE("onInputChannelCreated_native"); 898 if (handle != 0) { 899 NativeCode* code = (NativeCode*)handle; 900 status_t err = code->setInputChannel(channel); 901 if (err != OK) { 902 jniThrowException(env, "java/lang/IllegalStateException", 903 "Error setting input channel"); 904 return; 905 } 906 if (code->callbacks.onInputQueueCreated != NULL) { 907 code->callbacks.onInputQueueCreated(code, 908 code->nativeInputQueue); 909 } 910 } 911} 912 913static void 914onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel) 915{ 916 LOG_TRACE("onInputChannelDestroyed_native"); 917 if (handle != 0) { 918 NativeCode* code = (NativeCode*)handle; 919 if (code->nativeInputQueue != NULL 920 && code->callbacks.onInputQueueDestroyed != NULL) { 921 code->callbacks.onInputQueueDestroyed(code, 922 code->nativeInputQueue); 923 } 924 code->setInputChannel(NULL); 925 } 926} 927 928static void 929onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle, 930 jint x, jint y, jint w, jint h) 931{ 932 LOG_TRACE("onContentRectChanged_native"); 933 if (handle != 0) { 934 NativeCode* code = (NativeCode*)handle; 935 if (code->callbacks.onContentRectChanged != NULL) { 936 ARect rect; 937 rect.left = x; 938 rect.top = y; 939 rect.right = x+w; 940 rect.bottom = y+h; 941 code->callbacks.onContentRectChanged(code, &rect); 942 } 943 } 944} 945 946static void 947dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj) 948{ 949 LOG_TRACE("dispatchKeyEvent_native"); 950 if (handle != 0) { 951 NativeCode* code = (NativeCode*)handle; 952 if (code->nativeInputQueue != NULL) { 953 KeyEvent* event = code->nativeInputQueue->createKeyEvent(); 954 android_view_KeyEvent_toNative(env, eventObj, event); 955 code->nativeInputQueue->dispatchEvent(event); 956 } 957 } 958} 959 960static void 961finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, 962 jint seq, jboolean handled) 963{ 964 LOG_TRACE("finishPreDispatchKeyEvent_native"); 965 if (handle != 0) { 966 NativeCode* code = (NativeCode*)handle; 967 if (code->nativeInputQueue != NULL) { 968 code->nativeInputQueue->finishPreDispatch(seq, handled ? true : false); 969 } 970 } 971} 972 973static const JNINativeMethod g_methods[] = { 974 { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", 975 (void*)loadNativeCode_native }, 976 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, 977 { "onStartNative", "(I)V", (void*)onStart_native }, 978 { "onResumeNative", "(I)V", (void*)onResume_native }, 979 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native }, 980 { "onPauseNative", "(I)V", (void*)onPause_native }, 981 { "onStopNative", "(I)V", (void*)onStop_native }, 982 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native }, 983 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, 984 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, 985 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native }, 986 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native }, 987 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native }, 988 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native }, 989 { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native }, 990 { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native }, 991 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native }, 992 { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native }, 993 { "finishPreDispatchKeyEventNative", "(IIZ)V", (void*)finishPreDispatchKeyEvent_native }, 994}; 995 996static const char* const kNativeActivityPathName = "android/app/NativeActivity"; 997 998#define FIND_CLASS(var, className) \ 999 var = env->FindClass(className); \ 1000 LOG_FATAL_IF(! var, "Unable to find class " className); \ 1001 var = jclass(env->NewGlobalRef(var)); 1002 1003#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 1004 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 1005 LOG_FATAL_IF(! var, "Unable to find method" methodName); 1006 1007int register_android_app_NativeActivity(JNIEnv* env) 1008{ 1009 //LOGD("register_android_app_NativeActivity"); 1010 1011 FIND_CLASS(gNativeActivityClassInfo.clazz, kNativeActivityPathName); 1012 1013 GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, 1014 gNativeActivityClassInfo.clazz, 1015 "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V"); 1016 GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent, 1017 gNativeActivityClassInfo.clazz, 1018 "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V"); 1019 1020 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags, 1021 gNativeActivityClassInfo.clazz, 1022 "setWindowFlags", "(II)V"); 1023 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat, 1024 gNativeActivityClassInfo.clazz, 1025 "setWindowFormat", "(I)V"); 1026 GET_METHOD_ID(gNativeActivityClassInfo.showIme, 1027 gNativeActivityClassInfo.clazz, 1028 "showIme", "(I)V"); 1029 GET_METHOD_ID(gNativeActivityClassInfo.hideIme, 1030 gNativeActivityClassInfo.clazz, 1031 "hideIme", "(I)V"); 1032 1033 return AndroidRuntime::registerNativeMethods( 1034 env, kNativeActivityPathName, 1035 g_methods, NELEM(g_methods)); 1036} 1037 1038} // namespace android 1039