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