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