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
52namespace android
53{
54
55static const bool kLogTrace = false;
56
57static struct {
58    jmethodID finish;
59    jmethodID setWindowFlags;
60    jmethodID setWindowFormat;
61    jmethodID showIme;
62    jmethodID hideIme;
63} gNativeActivityClassInfo;
64
65// ------------------------------------------------------------------------
66
67struct ActivityWork {
68    int32_t cmd;
69    int32_t arg1;
70    int32_t arg2;
71};
72
73enum {
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
81static 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
91restart:
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
103static 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 */
116struct NativeCode : public ANativeActivity {
117    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
126    ~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
147    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
174void android_NativeActivity_finish(ANativeActivity* activity) {
175    NativeCode* code = static_cast<NativeCode*>(activity);
176    write_work(code->mainWorkWrite, CMD_FINISH, 0);
177}
178
179void 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
185void 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
191void 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
197void 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 */
208static 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
258static jlong
259loadNativeCode_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
367static jstring getDlError_native(JNIEnv* env, jobject clazz) {
368  return env->NewStringUTF(dlerror());
369}
370
371static void
372unloadNativeCode_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
383static void
384onStart_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
397static void
398onResume_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
411static jbyteArray
412onSaveInstanceState_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
440static void
441onPause_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
454static void
455onStop_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
468static void
469onConfigurationChanged_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
482static void
483onLowMemory_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
496static void
497onWindowFocusChanged_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
510static void
511onSurfaceCreated_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
526static 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
532static void
533onSurfaceChanged_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
575static void
576onSurfaceRedrawNeeded_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
589static void
590onSurfaceDestroyed_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
605static void
606onInputQueueCreated_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
620static void
621onInputQueueDestroyed_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
635static void
636onContentRectChanged_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
655static 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
680static const char* const kNativeActivityPathName = "android/app/NativeActivity";
681
682int 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