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