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