• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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