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
54namespace android
55{
56
57static const bool kLogTrace = false;
58
59static struct {
60    jmethodID finish;
61    jmethodID setWindowFlags;
62    jmethodID setWindowFormat;
63    jmethodID showIme;
64    jmethodID hideIme;
65} gNativeActivityClassInfo;
66
67// ------------------------------------------------------------------------
68
69struct ActivityWork {
70    int32_t cmd;
71    int32_t arg1;
72    int32_t arg2;
73};
74
75enum {
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
83static 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
93restart:
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
105static 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 */
118struct NativeCode : public ANativeActivity {
119    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
128    ~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
154    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
185void android_NativeActivity_finish(ANativeActivity* activity) {
186    NativeCode* code = static_cast<NativeCode*>(activity);
187    write_work(code->mainWorkWrite, CMD_FINISH, 0);
188}
189
190void 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
196void 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
202void 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
208void 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 */
219static 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
269static thread_local std::string g_error_msg;
270
271static jlong
272loadNativeCode_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
389static 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
395static void
396unloadNativeCode_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
407static void
408onStart_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
421static void
422onResume_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
435static jbyteArray
436onSaveInstanceState_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
464static void
465onPause_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
478static void
479onStop_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
492static void
493onConfigurationChanged_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
506static void
507onLowMemory_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
520static void
521onWindowFocusChanged_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
534static void
535onSurfaceCreated_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
550static 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
556static void
557onSurfaceChanged_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
599static void
600onSurfaceRedrawNeeded_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
613static void
614onSurfaceDestroyed_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
629static void
630onInputQueueCreated_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
644static void
645onInputQueueDestroyed_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
659static void
660onContentRectChanged_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
679static 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
704static const char* const kNativeActivityPathName = "android/app/NativeActivity";
705
706int 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