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