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 #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
write_work(int fd,int32_t cmd,int32_t arg1=0,int32_t arg2=0)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
read_work(int fd,ActivityWork * outWork)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 {
NativeCodeandroid::NativeCode105 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
~NativeCodeandroid::NativeCode114 ~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
setSurfaceandroid::NativeCode135 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
android_NativeActivity_finish(ANativeActivity * activity)162 void android_NativeActivity_finish(ANativeActivity* activity) {
163 NativeCode* code = static_cast<NativeCode*>(activity);
164 write_work(code->mainWorkWrite, CMD_FINISH, 0);
165 }
166
android_NativeActivity_setWindowFormat(ANativeActivity * activity,int32_t format)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
android_NativeActivity_setWindowFlags(ANativeActivity * activity,int32_t values,int32_t mask)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
android_NativeActivity_showSoftInput(ANativeActivity * activity,int32_t flags)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
android_NativeActivity_hideSoftInput(ANativeActivity * activity,int32_t flags)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 */
mainWorkCallback(int fd,int events,void * data)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
loadNativeCode_native(JNIEnv * env,jobject clazz,jstring path,jstring funcName,jobject messageQueue,jstring internalDataDir,jstring obbDir,jstring externalDataDir,int sdkVersion,jobject jAssetMgr,jbyteArray savedState)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 if (externalDataDir != NULL) {
310 dirStr = env->GetStringUTFChars(externalDataDir, NULL);
311 code->externalDataPathObj = dirStr;
312 env->ReleaseStringUTFChars(externalDataDir, dirStr);
313 }
314 code->externalDataPath = code->externalDataPathObj.string();
315
316 code->sdkVersion = sdkVersion;
317
318 code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
319
320 if (obbDir != NULL) {
321 dirStr = env->GetStringUTFChars(obbDir, NULL);
322 code->obbPathObj = dirStr;
323 env->ReleaseStringUTFChars(obbDir, dirStr);
324 }
325 code->obbPath = code->obbPathObj.string();
326
327 jbyte* rawSavedState = NULL;
328 jsize rawSavedSize = 0;
329 if (savedState != NULL) {
330 rawSavedState = env->GetByteArrayElements(savedState, NULL);
331 rawSavedSize = env->GetArrayLength(savedState);
332 }
333
334 code->createActivityFunc(code, rawSavedState, rawSavedSize);
335
336 if (rawSavedState != NULL) {
337 env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
338 }
339 }
340
341 return (jint)code;
342 }
343
344 static void
unloadNativeCode_native(JNIEnv * env,jobject clazz,jint handle)345 unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
346 {
347 LOG_TRACE("unloadNativeCode_native");
348 if (handle != 0) {
349 NativeCode* code = (NativeCode*)handle;
350 delete code;
351 }
352 }
353
354 static void
onStart_native(JNIEnv * env,jobject clazz,jint handle)355 onStart_native(JNIEnv* env, jobject clazz, jint handle)
356 {
357 LOG_TRACE("onStart_native");
358 if (handle != 0) {
359 NativeCode* code = (NativeCode*)handle;
360 if (code->callbacks.onStart != NULL) {
361 code->callbacks.onStart(code);
362 }
363 }
364 }
365
366 static void
onResume_native(JNIEnv * env,jobject clazz,jint handle)367 onResume_native(JNIEnv* env, jobject clazz, jint handle)
368 {
369 LOG_TRACE("onResume_native");
370 if (handle != 0) {
371 NativeCode* code = (NativeCode*)handle;
372 if (code->callbacks.onResume != NULL) {
373 code->callbacks.onResume(code);
374 }
375 }
376 }
377
378 static jbyteArray
onSaveInstanceState_native(JNIEnv * env,jobject clazz,jint handle)379 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
380 {
381 LOG_TRACE("onSaveInstanceState_native");
382
383 jbyteArray array = NULL;
384
385 if (handle != 0) {
386 NativeCode* code = (NativeCode*)handle;
387 if (code->callbacks.onSaveInstanceState != NULL) {
388 size_t len = 0;
389 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len);
390 if (len > 0) {
391 array = env->NewByteArray(len);
392 if (array != NULL) {
393 env->SetByteArrayRegion(array, 0, len, state);
394 }
395 }
396 if (state != NULL) {
397 free(state);
398 }
399 }
400 }
401
402 return array;
403 }
404
405 static void
onPause_native(JNIEnv * env,jobject clazz,jint handle)406 onPause_native(JNIEnv* env, jobject clazz, jint handle)
407 {
408 LOG_TRACE("onPause_native");
409 if (handle != 0) {
410 NativeCode* code = (NativeCode*)handle;
411 if (code->callbacks.onPause != NULL) {
412 code->callbacks.onPause(code);
413 }
414 }
415 }
416
417 static void
onStop_native(JNIEnv * env,jobject clazz,jint handle)418 onStop_native(JNIEnv* env, jobject clazz, jint handle)
419 {
420 LOG_TRACE("onStop_native");
421 if (handle != 0) {
422 NativeCode* code = (NativeCode*)handle;
423 if (code->callbacks.onStop != NULL) {
424 code->callbacks.onStop(code);
425 }
426 }
427 }
428
429 static void
onConfigurationChanged_native(JNIEnv * env,jobject clazz,jint handle)430 onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle)
431 {
432 LOG_TRACE("onConfigurationChanged_native");
433 if (handle != 0) {
434 NativeCode* code = (NativeCode*)handle;
435 if (code->callbacks.onConfigurationChanged != NULL) {
436 code->callbacks.onConfigurationChanged(code);
437 }
438 }
439 }
440
441 static void
onLowMemory_native(JNIEnv * env,jobject clazz,jint handle)442 onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
443 {
444 LOG_TRACE("onLowMemory_native");
445 if (handle != 0) {
446 NativeCode* code = (NativeCode*)handle;
447 if (code->callbacks.onLowMemory != NULL) {
448 code->callbacks.onLowMemory(code);
449 }
450 }
451 }
452
453 static void
onWindowFocusChanged_native(JNIEnv * env,jobject clazz,jint handle,jboolean focused)454 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
455 {
456 LOG_TRACE("onWindowFocusChanged_native");
457 if (handle != 0) {
458 NativeCode* code = (NativeCode*)handle;
459 if (code->callbacks.onWindowFocusChanged != NULL) {
460 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
461 }
462 }
463 }
464
465 static void
onSurfaceCreated_native(JNIEnv * env,jobject clazz,jint handle,jobject surface)466 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
467 {
468 LOG_TRACE("onSurfaceCreated_native");
469 if (handle != 0) {
470 NativeCode* code = (NativeCode*)handle;
471 code->setSurface(surface);
472 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
473 code->callbacks.onNativeWindowCreated(code,
474 code->nativeWindow.get());
475 }
476 }
477 }
478
getWindowProp(ANativeWindow * window,int what)479 static int32_t getWindowProp(ANativeWindow* window, int what) {
480 int value;
481 int res = window->query(window, what, &value);
482 return res < 0 ? res : value;
483 }
484
485 static void
onSurfaceChanged_native(JNIEnv * env,jobject clazz,jint handle,jobject surface,jint format,jint width,jint height)486 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
487 jint format, jint width, jint height)
488 {
489 LOG_TRACE("onSurfaceChanged_native");
490 if (handle != 0) {
491 NativeCode* code = (NativeCode*)handle;
492 sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
493 code->setSurface(surface);
494 if (oldNativeWindow != code->nativeWindow) {
495 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
496 code->callbacks.onNativeWindowDestroyed(code,
497 oldNativeWindow.get());
498 }
499 if (code->nativeWindow != NULL) {
500 if (code->callbacks.onNativeWindowCreated != NULL) {
501 code->callbacks.onNativeWindowCreated(code,
502 code->nativeWindow.get());
503 }
504 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
505 NATIVE_WINDOW_WIDTH);
506 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
507 NATIVE_WINDOW_HEIGHT);
508 }
509 } else {
510 // Maybe it resized?
511 int32_t newWidth = getWindowProp(code->nativeWindow.get(),
512 NATIVE_WINDOW_WIDTH);
513 int32_t newHeight = getWindowProp(code->nativeWindow.get(),
514 NATIVE_WINDOW_HEIGHT);
515 if (newWidth != code->lastWindowWidth
516 || newHeight != code->lastWindowHeight) {
517 if (code->callbacks.onNativeWindowResized != NULL) {
518 code->callbacks.onNativeWindowResized(code,
519 code->nativeWindow.get());
520 }
521 }
522 }
523 }
524 }
525
526 static void
onSurfaceRedrawNeeded_native(JNIEnv * env,jobject clazz,jint handle)527 onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
528 {
529 LOG_TRACE("onSurfaceRedrawNeeded_native");
530 if (handle != 0) {
531 NativeCode* code = (NativeCode*)handle;
532 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
533 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
534 }
535 }
536 }
537
538 static void
onSurfaceDestroyed_native(JNIEnv * env,jobject clazz,jint handle,jobject surface)539 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
540 {
541 LOG_TRACE("onSurfaceDestroyed_native");
542 if (handle != 0) {
543 NativeCode* code = (NativeCode*)handle;
544 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
545 code->callbacks.onNativeWindowDestroyed(code,
546 code->nativeWindow.get());
547 }
548 code->setSurface(NULL);
549 }
550 }
551
552 static void
onInputQueueCreated_native(JNIEnv * env,jobject clazz,jint handle,jint queuePtr)553 onInputQueueCreated_native(JNIEnv* env, jobject clazz, jint handle, jint queuePtr)
554 {
555 LOG_TRACE("onInputChannelCreated_native");
556 if (handle != 0) {
557 NativeCode* code = (NativeCode*)handle;
558 if (code->callbacks.onInputQueueCreated != NULL) {
559 AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr);
560 code->callbacks.onInputQueueCreated(code, queue);
561 }
562 }
563 }
564
565 static void
onInputQueueDestroyed_native(JNIEnv * env,jobject clazz,jint handle,jint queuePtr)566 onInputQueueDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jint queuePtr)
567 {
568 LOG_TRACE("onInputChannelDestroyed_native");
569 if (handle != 0) {
570 NativeCode* code = (NativeCode*)handle;
571 if (code->callbacks.onInputQueueDestroyed != NULL) {
572 AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr);
573 code->callbacks.onInputQueueDestroyed(code, queue);
574 }
575 }
576 }
577
578 static void
onContentRectChanged_native(JNIEnv * env,jobject clazz,jint handle,jint x,jint y,jint w,jint h)579 onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
580 jint x, jint y, jint w, jint h)
581 {
582 LOG_TRACE("onContentRectChanged_native");
583 if (handle != 0) {
584 NativeCode* code = (NativeCode*)handle;
585 if (code->callbacks.onContentRectChanged != NULL) {
586 ARect rect;
587 rect.left = x;
588 rect.top = y;
589 rect.right = x+w;
590 rect.bottom = y+h;
591 code->callbacks.onContentRectChanged(code, &rect);
592 }
593 }
594 }
595
596 static const JNINativeMethod g_methods[] = {
597 { "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",
598 (void*)loadNativeCode_native },
599 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
600 { "onStartNative", "(I)V", (void*)onStart_native },
601 { "onResumeNative", "(I)V", (void*)onResume_native },
602 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native },
603 { "onPauseNative", "(I)V", (void*)onPause_native },
604 { "onStopNative", "(I)V", (void*)onStop_native },
605 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native },
606 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
607 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
608 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
609 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
610 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
611 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
612 { "onInputQueueCreatedNative", "(II)V",
613 (void*)onInputQueueCreated_native },
614 { "onInputQueueDestroyedNative", "(II)V",
615 (void*)onInputQueueDestroyed_native },
616 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
617 };
618
619 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
620
621 #define FIND_CLASS(var, className) \
622 var = env->FindClass(className); \
623 LOG_FATAL_IF(! var, "Unable to find class %s", className);
624
625 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
626 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
627 LOG_FATAL_IF(! var, "Unable to find method" methodName);
628
register_android_app_NativeActivity(JNIEnv * env)629 int register_android_app_NativeActivity(JNIEnv* env)
630 {
631 //ALOGD("register_android_app_NativeActivity");
632 jclass clazz;
633 FIND_CLASS(clazz, kNativeActivityPathName);
634
635 GET_METHOD_ID(gNativeActivityClassInfo.finish,
636 clazz,
637 "finish", "()V");
638 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
639 clazz,
640 "setWindowFlags", "(II)V");
641 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
642 clazz,
643 "setWindowFormat", "(I)V");
644 GET_METHOD_ID(gNativeActivityClassInfo.showIme,
645 clazz,
646 "showIme", "(I)V");
647 GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
648 clazz,
649 "hideIme", "(I)V");
650
651 return AndroidRuntime::registerNativeMethods(
652 env, kNativeActivityPathName,
653 g_methods, NELEM(g_methods));
654 }
655
656 } // namespace android
657