android_app_NativeActivity.cpp revision a44dd26a75e24cc021802288fb81f4761e47be6b
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 44namespace android 45{ 46 47static struct { 48 jmethodID finish; 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_FINISH = 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) ALOGW("Failed writing to work fd: %s", strerror(errno)); 88 else ALOGW("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) ALOGW("Failed reading work fd: %s", strerror(errno)); 97 else ALOGW("Truncated reading work fd: %d", res); 98 return false; 99} 100 101/* 102 * Native state for interacting with the NativeActivity class. 103 */ 104struct NativeCode : public ANativeActivity { 105 NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { 106 memset((ANativeActivity*)this, 0, sizeof(ANativeActivity)); 107 memset(&callbacks, 0, sizeof(callbacks)); 108 dlhandle = _dlhandle; 109 createActivityFunc = _createFunc; 110 nativeWindow = NULL; 111 mainWorkRead = mainWorkWrite = -1; 112 } 113 114 ~NativeCode() { 115 if (callbacks.onDestroy != NULL) { 116 callbacks.onDestroy(this); 117 } 118 if (env != NULL && clazz != NULL) { 119 env->DeleteGlobalRef(clazz); 120 } 121 if (messageQueue != NULL && mainWorkRead >= 0) { 122 messageQueue->getLooper()->removeFd(mainWorkRead); 123 } 124 setSurface(NULL); 125 if (mainWorkRead >= 0) close(mainWorkRead); 126 if (mainWorkWrite >= 0) close(mainWorkWrite); 127 if (dlhandle != NULL) { 128 // for now don't unload... we probably should clean this 129 // up and only keep one open dlhandle per proc, since there 130 // is really no benefit to unloading the code. 131 //dlclose(dlhandle); 132 } 133 } 134 135 void setSurface(jobject _surface) { 136 if (_surface != NULL) { 137 nativeWindow = android_view_Surface_getNativeWindow(env, _surface); 138 } else { 139 nativeWindow = NULL; 140 } 141 } 142 143 ANativeActivityCallbacks callbacks; 144 145 void* dlhandle; 146 ANativeActivity_createFunc* createActivityFunc; 147 148 String8 internalDataPathObj; 149 String8 externalDataPathObj; 150 String8 obbPathObj; 151 152 sp<ANativeWindow> nativeWindow; 153 int32_t lastWindowWidth; 154 int32_t lastWindowHeight; 155 156 // These are used to wake up the main thread to process work. 157 int mainWorkRead; 158 int mainWorkWrite; 159 sp<MessageQueue> messageQueue; 160}; 161 162void android_NativeActivity_finish(ANativeActivity* activity) { 163 NativeCode* code = static_cast<NativeCode*>(activity); 164 write_work(code->mainWorkWrite, CMD_FINISH, 0); 165} 166 167void android_NativeActivity_setWindowFormat( 168 ANativeActivity* activity, int32_t format) { 169 NativeCode* code = static_cast<NativeCode*>(activity); 170 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format); 171} 172 173void android_NativeActivity_setWindowFlags( 174 ANativeActivity* activity, int32_t values, int32_t mask) { 175 NativeCode* code = static_cast<NativeCode*>(activity); 176 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask); 177} 178 179void android_NativeActivity_showSoftInput( 180 ANativeActivity* activity, int32_t flags) { 181 NativeCode* code = static_cast<NativeCode*>(activity); 182 write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags); 183} 184 185void android_NativeActivity_hideSoftInput( 186 ANativeActivity* activity, int32_t flags) { 187 NativeCode* code = static_cast<NativeCode*>(activity); 188 write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags); 189} 190 191// ------------------------------------------------------------------------ 192 193/* 194 * Callback for handling native events on the application's main thread. 195 */ 196static int mainWorkCallback(int fd, int events, void* data) { 197 NativeCode* code = (NativeCode*)data; 198 if ((events & POLLIN) == 0) { 199 return 1; 200 } 201 202 ActivityWork work; 203 if (!read_work(code->mainWorkRead, &work)) { 204 return 1; 205 } 206 207 LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd); 208 209 switch (work.cmd) { 210 case CMD_FINISH: { 211 code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish); 212 code->messageQueue->raiseAndClearException(code->env, "finish"); 213 } break; 214 case CMD_SET_WINDOW_FORMAT: { 215 code->env->CallVoidMethod(code->clazz, 216 gNativeActivityClassInfo.setWindowFormat, work.arg1); 217 code->messageQueue->raiseAndClearException(code->env, "setWindowFormat"); 218 } break; 219 case CMD_SET_WINDOW_FLAGS: { 220 code->env->CallVoidMethod(code->clazz, 221 gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2); 222 code->messageQueue->raiseAndClearException(code->env, "setWindowFlags"); 223 } break; 224 case CMD_SHOW_SOFT_INPUT: { 225 code->env->CallVoidMethod(code->clazz, 226 gNativeActivityClassInfo.showIme, work.arg1); 227 code->messageQueue->raiseAndClearException(code->env, "showIme"); 228 } break; 229 case CMD_HIDE_SOFT_INPUT: { 230 code->env->CallVoidMethod(code->clazz, 231 gNativeActivityClassInfo.hideIme, work.arg1); 232 code->messageQueue->raiseAndClearException(code->env, "hideIme"); 233 } break; 234 default: 235 ALOGW("Unknown work command: %d", work.cmd); 236 break; 237 } 238 239 return 1; 240} 241 242// ------------------------------------------------------------------------ 243 244static jint 245loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName, 246 jobject messageQueue, jstring internalDataDir, jstring obbDir, 247 jstring externalDataDir, int sdkVersion, 248 jobject jAssetMgr, jbyteArray savedState) 249{ 250 LOG_TRACE("loadNativeCode_native"); 251 252 const char* pathStr = env->GetStringUTFChars(path, NULL); 253 NativeCode* code = NULL; 254 255 void* handle = dlopen(pathStr, RTLD_LAZY); 256 257 env->ReleaseStringUTFChars(path, pathStr); 258 259 if (handle != NULL) { 260 const char* funcStr = env->GetStringUTFChars(funcName, NULL); 261 code = new NativeCode(handle, (ANativeActivity_createFunc*) 262 dlsym(handle, funcStr)); 263 env->ReleaseStringUTFChars(funcName, funcStr); 264 265 if (code->createActivityFunc == NULL) { 266 ALOGW("ANativeActivity_onCreate not found"); 267 delete code; 268 return 0; 269 } 270 271 code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue); 272 if (code->messageQueue == NULL) { 273 ALOGW("Unable to retrieve native MessageQueue"); 274 delete code; 275 return 0; 276 } 277 278 int msgpipe[2]; 279 if (pipe(msgpipe)) { 280 ALOGW("could not create pipe: %s", strerror(errno)); 281 delete code; 282 return 0; 283 } 284 code->mainWorkRead = msgpipe[0]; 285 code->mainWorkWrite = msgpipe[1]; 286 int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); 287 SLOGW_IF(result != 0, "Could not make main work read pipe " 288 "non-blocking: %s", strerror(errno)); 289 result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); 290 SLOGW_IF(result != 0, "Could not make main work write pipe " 291 "non-blocking: %s", strerror(errno)); 292 code->messageQueue->getLooper()->addFd( 293 code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); 294 295 code->ANativeActivity::callbacks = &code->callbacks; 296 if (env->GetJavaVM(&code->vm) < 0) { 297 ALOGW("NativeActivity GetJavaVM failed"); 298 delete code; 299 return 0; 300 } 301 code->env = env; 302 code->clazz = env->NewGlobalRef(clazz); 303 304 const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL); 305 code->internalDataPathObj = dirStr; 306 code->internalDataPath = code->internalDataPathObj.string(); 307 env->ReleaseStringUTFChars(internalDataDir, dirStr); 308 309 dirStr = env->GetStringUTFChars(externalDataDir, NULL); 310 code->externalDataPathObj = dirStr; 311 code->externalDataPath = code->externalDataPathObj.string(); 312 env->ReleaseStringUTFChars(externalDataDir, dirStr); 313 314 code->sdkVersion = sdkVersion; 315 316 code->assetManager = assetManagerForJavaObject(env, jAssetMgr); 317 318 dirStr = env->GetStringUTFChars(obbDir, NULL); 319 code->obbPathObj = dirStr; 320 code->obbPath = code->obbPathObj.string(); 321 env->ReleaseStringUTFChars(obbDir, dirStr); 322 323 jbyte* rawSavedState = NULL; 324 jsize rawSavedSize = 0; 325 if (savedState != NULL) { 326 rawSavedState = env->GetByteArrayElements(savedState, NULL); 327 rawSavedSize = env->GetArrayLength(savedState); 328 } 329 330 code->createActivityFunc(code, rawSavedState, rawSavedSize); 331 332 if (rawSavedState != NULL) { 333 env->ReleaseByteArrayElements(savedState, rawSavedState, 0); 334 } 335 } 336 337 return (jint)code; 338} 339 340static void 341unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle) 342{ 343 LOG_TRACE("unloadNativeCode_native"); 344 if (handle != 0) { 345 NativeCode* code = (NativeCode*)handle; 346 delete code; 347 } 348} 349 350static void 351onStart_native(JNIEnv* env, jobject clazz, jint handle) 352{ 353 LOG_TRACE("onStart_native"); 354 if (handle != 0) { 355 NativeCode* code = (NativeCode*)handle; 356 if (code->callbacks.onStart != NULL) { 357 code->callbacks.onStart(code); 358 } 359 } 360} 361 362static void 363onResume_native(JNIEnv* env, jobject clazz, jint handle) 364{ 365 LOG_TRACE("onResume_native"); 366 if (handle != 0) { 367 NativeCode* code = (NativeCode*)handle; 368 if (code->callbacks.onResume != NULL) { 369 code->callbacks.onResume(code); 370 } 371 } 372} 373 374static jbyteArray 375onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) 376{ 377 LOG_TRACE("onSaveInstanceState_native"); 378 379 jbyteArray array = NULL; 380 381 if (handle != 0) { 382 NativeCode* code = (NativeCode*)handle; 383 if (code->callbacks.onSaveInstanceState != NULL) { 384 size_t len = 0; 385 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len); 386 if (len > 0) { 387 array = env->NewByteArray(len); 388 if (array != NULL) { 389 env->SetByteArrayRegion(array, 0, len, state); 390 } 391 } 392 if (state != NULL) { 393 free(state); 394 } 395 } 396 } 397 398 return array; 399} 400 401static void 402onPause_native(JNIEnv* env, jobject clazz, jint handle) 403{ 404 LOG_TRACE("onPause_native"); 405 if (handle != 0) { 406 NativeCode* code = (NativeCode*)handle; 407 if (code->callbacks.onPause != NULL) { 408 code->callbacks.onPause(code); 409 } 410 } 411} 412 413static void 414onStop_native(JNIEnv* env, jobject clazz, jint handle) 415{ 416 LOG_TRACE("onStop_native"); 417 if (handle != 0) { 418 NativeCode* code = (NativeCode*)handle; 419 if (code->callbacks.onStop != NULL) { 420 code->callbacks.onStop(code); 421 } 422 } 423} 424 425static void 426onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle) 427{ 428 LOG_TRACE("onConfigurationChanged_native"); 429 if (handle != 0) { 430 NativeCode* code = (NativeCode*)handle; 431 if (code->callbacks.onConfigurationChanged != NULL) { 432 code->callbacks.onConfigurationChanged(code); 433 } 434 } 435} 436 437static void 438onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) 439{ 440 LOG_TRACE("onLowMemory_native"); 441 if (handle != 0) { 442 NativeCode* code = (NativeCode*)handle; 443 if (code->callbacks.onLowMemory != NULL) { 444 code->callbacks.onLowMemory(code); 445 } 446 } 447} 448 449static void 450onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused) 451{ 452 LOG_TRACE("onWindowFocusChanged_native"); 453 if (handle != 0) { 454 NativeCode* code = (NativeCode*)handle; 455 if (code->callbacks.onWindowFocusChanged != NULL) { 456 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); 457 } 458 } 459} 460 461static void 462onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 463{ 464 LOG_TRACE("onSurfaceCreated_native"); 465 if (handle != 0) { 466 NativeCode* code = (NativeCode*)handle; 467 code->setSurface(surface); 468 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) { 469 code->callbacks.onNativeWindowCreated(code, 470 code->nativeWindow.get()); 471 } 472 } 473} 474 475static int32_t getWindowProp(ANativeWindow* window, int what) { 476 int value; 477 int res = window->query(window, what, &value); 478 return res < 0 ? res : value; 479} 480 481static void 482onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface, 483 jint format, jint width, jint height) 484{ 485 LOG_TRACE("onSurfaceChanged_native"); 486 if (handle != 0) { 487 NativeCode* code = (NativeCode*)handle; 488 sp<ANativeWindow> oldNativeWindow = code->nativeWindow; 489 code->setSurface(surface); 490 if (oldNativeWindow != code->nativeWindow) { 491 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 492 code->callbacks.onNativeWindowDestroyed(code, 493 oldNativeWindow.get()); 494 } 495 if (code->nativeWindow != NULL) { 496 if (code->callbacks.onNativeWindowCreated != NULL) { 497 code->callbacks.onNativeWindowCreated(code, 498 code->nativeWindow.get()); 499 } 500 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(), 501 NATIVE_WINDOW_WIDTH); 502 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(), 503 NATIVE_WINDOW_HEIGHT); 504 } 505 } else { 506 // Maybe it resized? 507 int32_t newWidth = getWindowProp(code->nativeWindow.get(), 508 NATIVE_WINDOW_WIDTH); 509 int32_t newHeight = getWindowProp(code->nativeWindow.get(), 510 NATIVE_WINDOW_HEIGHT); 511 if (newWidth != code->lastWindowWidth 512 || newHeight != code->lastWindowHeight) { 513 if (code->callbacks.onNativeWindowResized != NULL) { 514 code->callbacks.onNativeWindowResized(code, 515 code->nativeWindow.get()); 516 } 517 } 518 } 519 } 520} 521 522static void 523onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle) 524{ 525 LOG_TRACE("onSurfaceRedrawNeeded_native"); 526 if (handle != 0) { 527 NativeCode* code = (NativeCode*)handle; 528 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) { 529 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get()); 530 } 531 } 532} 533 534static void 535onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 536{ 537 LOG_TRACE("onSurfaceDestroyed_native"); 538 if (handle != 0) { 539 NativeCode* code = (NativeCode*)handle; 540 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 541 code->callbacks.onNativeWindowDestroyed(code, 542 code->nativeWindow.get()); 543 } 544 code->setSurface(NULL); 545 } 546} 547 548static void 549onInputQueueCreated_native(JNIEnv* env, jobject clazz, jint handle, jint queuePtr) 550{ 551 LOG_TRACE("onInputChannelCreated_native"); 552 if (handle != 0) { 553 NativeCode* code = (NativeCode*)handle; 554 if (code->callbacks.onInputQueueCreated != NULL) { 555 AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr); 556 code->callbacks.onInputQueueCreated(code, queue); 557 } 558 } 559} 560 561static void 562onInputQueueDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jint queuePtr) 563{ 564 LOG_TRACE("onInputChannelDestroyed_native"); 565 if (handle != 0) { 566 NativeCode* code = (NativeCode*)handle; 567 if (code->callbacks.onInputQueueDestroyed != NULL) { 568 AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr); 569 code->callbacks.onInputQueueDestroyed(code, queue); 570 } 571 } 572} 573 574static void 575onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle, 576 jint x, jint y, jint w, jint h) 577{ 578 LOG_TRACE("onContentRectChanged_native"); 579 if (handle != 0) { 580 NativeCode* code = (NativeCode*)handle; 581 if (code->callbacks.onContentRectChanged != NULL) { 582 ARect rect; 583 rect.left = x; 584 rect.top = y; 585 rect.right = x+w; 586 rect.bottom = y+h; 587 code->callbacks.onContentRectChanged(code, &rect); 588 } 589 } 590} 591 592static const JNINativeMethod g_methods[] = { 593 { "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", 594 (void*)loadNativeCode_native }, 595 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, 596 { "onStartNative", "(I)V", (void*)onStart_native }, 597 { "onResumeNative", "(I)V", (void*)onResume_native }, 598 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native }, 599 { "onPauseNative", "(I)V", (void*)onPause_native }, 600 { "onStopNative", "(I)V", (void*)onStop_native }, 601 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native }, 602 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, 603 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, 604 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native }, 605 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native }, 606 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native }, 607 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native }, 608 { "onInputQueueCreatedNative", "(II)V", 609 (void*)onInputQueueCreated_native }, 610 { "onInputQueueDestroyedNative", "(II)V", 611 (void*)onInputQueueDestroyed_native }, 612 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native }, 613}; 614 615static const char* const kNativeActivityPathName = "android/app/NativeActivity"; 616 617#define FIND_CLASS(var, className) \ 618 var = env->FindClass(className); \ 619 LOG_FATAL_IF(! var, "Unable to find class %s", className); 620 621#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 622 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 623 LOG_FATAL_IF(! var, "Unable to find method" methodName); 624 625int register_android_app_NativeActivity(JNIEnv* env) 626{ 627 //ALOGD("register_android_app_NativeActivity"); 628 jclass clazz; 629 FIND_CLASS(clazz, kNativeActivityPathName); 630 631 GET_METHOD_ID(gNativeActivityClassInfo.finish, 632 clazz, 633 "finish", "()V"); 634 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags, 635 clazz, 636 "setWindowFlags", "(II)V"); 637 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat, 638 clazz, 639 "setWindowFormat", "(I)V"); 640 GET_METHOD_ID(gNativeActivityClassInfo.showIme, 641 clazz, 642 "showIme", "(I)V"); 643 GET_METHOD_ID(gNativeActivityClassInfo.hideIme, 644 clazz, 645 "hideIme", "(I)V"); 646 647 return AndroidRuntime::registerNativeMethods( 648 env, kNativeActivityPathName, 649 g_methods, NELEM(g_methods)); 650} 651 652} // namespace android 653