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