android_app_NativeActivity.cpp revision a95e4cb62f3642cb190d032dbf7dc40d9ecc6973
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 "JNIHelp.h"
21#include "android_view_InputChannel.h"
22#include <android_runtime/AndroidRuntime.h>
23#include <android/native_activity.h>
24#include <ui/InputTransport.h>
25
26#include <dlfcn.h>
27
28namespace android
29{
30
31struct NativeCode {
32    NativeCode(void* _dlhandle, android_activity_create_t* _createFunc) {
33        memset(&activity, sizeof(activity), 0);
34        memset(&callbacks, sizeof(callbacks), 0);
35        dlhandle = _dlhandle;
36        createActivityFunc = _createFunc;
37        surface = NULL;
38        inputChannel = NULL;
39        nativeInputQueue = NULL;
40    }
41
42    ~NativeCode() {
43        setSurface(NULL);
44        setInputChannel(NULL);
45        if (callbacks.onDestroy != NULL) {
46            callbacks.onDestroy(&activity);
47        }
48        if (dlhandle != NULL) {
49            dlclose(dlhandle);
50        }
51    }
52
53    void setSurface(jobject _surface) {
54        if (surface != NULL) {
55            activity.env->DeleteGlobalRef(surface);
56        }
57        if (_surface != NULL) {
58            surface = activity.env->NewGlobalRef(_surface);
59        } else {
60            surface = NULL;
61        }
62    }
63
64    status_t setInputChannel(jobject _channel) {
65        if (inputChannel != NULL) {
66            delete nativeInputQueue;
67            activity.env->DeleteGlobalRef(inputChannel);
68        }
69        inputChannel = NULL;
70        nativeInputQueue = NULL;
71        if (_channel != NULL) {
72            inputChannel = activity.env->NewGlobalRef(_channel);
73            sp<InputChannel> ic =
74                    android_view_InputChannel_getInputChannel(activity.env, _channel);
75            if (ic != NULL) {
76                nativeInputQueue = new input_queue_t(ic);
77                if (nativeInputQueue->getConsumer().initialize() != android::OK) {
78                    delete nativeInputQueue;
79                    nativeInputQueue = NULL;
80                    return UNKNOWN_ERROR;
81                }
82            } else {
83                return UNKNOWN_ERROR;
84            }
85        }
86        return OK;
87    }
88
89    android_activity_t activity;
90    android_activity_callbacks_t callbacks;
91
92    void* dlhandle;
93    android_activity_create_t* createActivityFunc;
94
95    jobject surface;
96    jobject inputChannel;
97    struct input_queue_t* nativeInputQueue;
98};
99
100static jint
101loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path)
102{
103    const char* pathStr = env->GetStringUTFChars(path, NULL);
104    NativeCode* code = NULL;
105
106    void* handle = dlopen(pathStr, RTLD_LAZY);
107
108    env->ReleaseStringUTFChars(path, pathStr);
109
110    if (handle != NULL) {
111        code = new NativeCode(handle, (android_activity_create_t*)
112                dlsym(handle, "android_onCreateActivity"));
113        if (code->createActivityFunc == NULL) {
114            LOGW("android_onCreateActivity not found");
115            delete code;
116            return 0;
117        }
118        code->activity.callbacks = &code->callbacks;
119        code->activity.env = env;
120        code->activity.clazz = clazz;
121        code->createActivityFunc(&code->activity, NULL, 0);
122    }
123
124    return (jint)code;
125}
126
127static void
128unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
129{
130    if (handle != 0) {
131        NativeCode* code = (NativeCode*)handle;
132        delete code;
133    }
134}
135
136static void
137onStart_native(JNIEnv* env, jobject clazz, jint handle)
138{
139    if (handle != 0) {
140        NativeCode* code = (NativeCode*)handle;
141        if (code->callbacks.onStart != NULL) {
142            code->callbacks.onStart(&code->activity);
143        }
144    }
145}
146
147static void
148onResume_native(JNIEnv* env, jobject clazz, jint handle)
149{
150    if (handle != 0) {
151        NativeCode* code = (NativeCode*)handle;
152        if (code->callbacks.onResume != NULL) {
153            code->callbacks.onResume(&code->activity);
154        }
155    }
156}
157
158static void
159onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
160{
161    if (handle != 0) {
162        NativeCode* code = (NativeCode*)handle;
163        if (code->callbacks.onSaveInstanceState != NULL) {
164            size_t len = 0;
165            code->callbacks.onSaveInstanceState(&code->activity, &len);
166        }
167    }
168}
169
170static void
171onPause_native(JNIEnv* env, jobject clazz, jint handle)
172{
173    if (handle != 0) {
174        NativeCode* code = (NativeCode*)handle;
175        if (code->callbacks.onPause != NULL) {
176            code->callbacks.onPause(&code->activity);
177        }
178    }
179}
180
181static void
182onStop_native(JNIEnv* env, jobject clazz, jint handle)
183{
184    if (handle != 0) {
185        NativeCode* code = (NativeCode*)handle;
186        if (code->callbacks.onStop != NULL) {
187            code->callbacks.onStop(&code->activity);
188        }
189    }
190}
191
192static void
193onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
194{
195    if (handle != 0) {
196        NativeCode* code = (NativeCode*)handle;
197        if (code->callbacks.onLowMemory != NULL) {
198            code->callbacks.onLowMemory(&code->activity);
199        }
200    }
201}
202
203static void
204onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
205{
206    if (handle != 0) {
207        NativeCode* code = (NativeCode*)handle;
208        if (code->callbacks.onWindowFocusChanged != NULL) {
209            code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
210        }
211    }
212}
213
214static void
215onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
216{
217    if (handle != 0) {
218        NativeCode* code = (NativeCode*)handle;
219        code->setSurface(surface);
220        if (code->callbacks.onSurfaceCreated != NULL) {
221            code->callbacks.onSurfaceCreated(&code->activity,
222                    (android_surface_t*)code->surface);
223        }
224    }
225}
226
227static void
228onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
229        jint format, jint width, jint height)
230{
231    if (handle != 0) {
232        NativeCode* code = (NativeCode*)handle;
233        if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) {
234            code->callbacks.onSurfaceChanged(&code->activity,
235                    (android_surface_t*)code->surface, format, width, height);
236        }
237    }
238}
239
240static void
241onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
242{
243    if (handle != 0) {
244        NativeCode* code = (NativeCode*)handle;
245        if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) {
246            code->callbacks.onSurfaceDestroyed(&code->activity,
247                    (android_surface_t*)code->surface);
248        }
249        code->setSurface(NULL);
250    }
251}
252
253static void
254onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
255{
256    if (handle != 0) {
257        NativeCode* code = (NativeCode*)handle;
258        status_t err = code->setInputChannel(channel);
259        if (err != OK) {
260            jniThrowException(env, "java/lang/IllegalStateException",
261                    "Error setting input channel");
262            return;
263        }
264        if (code->callbacks.onInputQueueCreated != NULL) {
265            code->callbacks.onInputQueueCreated(&code->activity,
266                    code->nativeInputQueue);
267        }
268    }
269}
270
271static void
272onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
273{
274    if (handle != 0) {
275        NativeCode* code = (NativeCode*)handle;
276        if (code->nativeInputQueue != NULL
277                && code->callbacks.onInputQueueDestroyed != NULL) {
278            code->callbacks.onInputQueueDestroyed(&code->activity,
279                    code->nativeInputQueue);
280        }
281        code->setInputChannel(NULL);
282    }
283}
284
285static const JNINativeMethod g_methods[] = {
286    { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
287    { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
288    { "onStartNative", "(I)V", (void*)onStart_native },
289    { "onResumeNative", "(I)V", (void*)onResume_native },
290    { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native },
291    { "onPauseNative", "(I)V", (void*)onPause_native },
292    { "onStopNative", "(I)V", (void*)onStop_native },
293    { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
294    { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
295    { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
296    { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
297    { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
298    { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
299    { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
300};
301
302static const char* const kNativeActivityPathName = "android/app/NativeActivity";
303
304int register_android_app_NativeActivity(JNIEnv* env)
305{
306    //LOGD("register_android_app_NativeActivity");
307
308    jclass clazz;
309
310    clazz = env->FindClass(kNativeActivityPathName);
311    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity");
312
313    return AndroidRuntime::registerNativeMethods(
314        env, kNativeActivityPathName,
315        g_methods, NELEM(g_methods));
316}
317
318} // namespace android
319