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