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