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