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 finish; 49 jmethodID setWindowFlags; 50 jmethodID setWindowFormat; 51 jmethodID showIme; 52 jmethodID hideIme; 53 } gNativeActivityClassInfo; 54 55 // ------------------------------------------------------------------------ 56 57 struct ActivityWork { 58 int32_t cmd; 59 int32_t arg1; 60 int32_t arg2; 61 }; 62 63 enum { 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 71 static 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 79 restart: 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 91 static 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 */ 104 struct 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 162 void android_NativeActivity_finish(ANativeActivity* activity) { 163 NativeCode* code = static_cast<NativeCode*>(activity); 164 write_work(code->mainWorkWrite, CMD_FINISH, 0); 165 } 166 167 void 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 173 void 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 179 void 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 185 void 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 */ 196 static 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 244 static jint 245 loadNativeCode_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 340 static void 341 unloadNativeCode_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 350 static void 351 onStart_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 362 static void 363 onResume_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 374 static jbyteArray 375 onSaveInstanceState_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 401 static void 402 onPause_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 413 static void 414 onStop_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 425 static void 426 onConfigurationChanged_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 437 static void 438 onLowMemory_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 449 static void 450 onWindowFocusChanged_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 461 static void 462 onSurfaceCreated_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 475 static 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 481 static void 482 onSurfaceChanged_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 522 static void 523 onSurfaceRedrawNeeded_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 534 static void 535 onSurfaceDestroyed_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 548 static void 549 onInputQueueCreated_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 561 static void 562 onInputQueueDestroyed_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 574 static void 575 onContentRectChanged_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 592 static 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 615 static 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 625 int 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