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