android_app_NativeActivity.cpp revision 2e9f93e8db509d5236229dc8540e0904c5dbb9f5
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, ANativeActivity_createFunc* _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 AInputQueue(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    ANativeActivity activity;
90    ANativeActivityCallbacks callbacks;
91
92    void* dlhandle;
93    ANativeActivity_createFunc* createActivityFunc;
94
95    jobject surface;
96    jobject inputChannel;
97    struct AInputQueue* 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, (ANativeActivity_createFunc*)
112                dlsym(handle, "ANativeActivity_onCreate"));
113        if (code->createActivityFunc == NULL) {
114            LOGW("ANativeActivity_onCreate not found");
115            delete code;
116            return 0;
117        }
118        code->activity.callbacks = &code->callbacks;
119        if (env->GetJavaVM(&code->activity.vm) < 0) {
120            LOGW("NativeActivity GetJavaVM failed");
121            delete code;
122            return 0;
123        }
124        code->activity.env = env;
125        code->activity.clazz = clazz;
126        code->createActivityFunc(&code->activity, NULL, 0);
127    }
128
129    return (jint)code;
130}
131
132static void
133unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
134{
135    if (handle != 0) {
136        NativeCode* code = (NativeCode*)handle;
137        delete code;
138    }
139}
140
141static void
142onStart_native(JNIEnv* env, jobject clazz, jint handle)
143{
144    if (handle != 0) {
145        NativeCode* code = (NativeCode*)handle;
146        if (code->callbacks.onStart != NULL) {
147            code->callbacks.onStart(&code->activity);
148        }
149    }
150}
151
152static void
153onResume_native(JNIEnv* env, jobject clazz, jint handle)
154{
155    if (handle != 0) {
156        NativeCode* code = (NativeCode*)handle;
157        if (code->callbacks.onResume != NULL) {
158            code->callbacks.onResume(&code->activity);
159        }
160    }
161}
162
163static void
164onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
165{
166    if (handle != 0) {
167        NativeCode* code = (NativeCode*)handle;
168        if (code->callbacks.onSaveInstanceState != NULL) {
169            size_t len = 0;
170            code->callbacks.onSaveInstanceState(&code->activity, &len);
171        }
172    }
173}
174
175static void
176onPause_native(JNIEnv* env, jobject clazz, jint handle)
177{
178    if (handle != 0) {
179        NativeCode* code = (NativeCode*)handle;
180        if (code->callbacks.onPause != NULL) {
181            code->callbacks.onPause(&code->activity);
182        }
183    }
184}
185
186static void
187onStop_native(JNIEnv* env, jobject clazz, jint handle)
188{
189    if (handle != 0) {
190        NativeCode* code = (NativeCode*)handle;
191        if (code->callbacks.onStop != NULL) {
192            code->callbacks.onStop(&code->activity);
193        }
194    }
195}
196
197static void
198onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
199{
200    if (handle != 0) {
201        NativeCode* code = (NativeCode*)handle;
202        if (code->callbacks.onLowMemory != NULL) {
203            code->callbacks.onLowMemory(&code->activity);
204        }
205    }
206}
207
208static void
209onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
210{
211    if (handle != 0) {
212        NativeCode* code = (NativeCode*)handle;
213        if (code->callbacks.onWindowFocusChanged != NULL) {
214            code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0);
215        }
216    }
217}
218
219static void
220onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
221{
222    if (handle != 0) {
223        NativeCode* code = (NativeCode*)handle;
224        code->setSurface(surface);
225        if (code->callbacks.onSurfaceCreated != NULL) {
226            code->callbacks.onSurfaceCreated(&code->activity,
227                    (ASurfaceHolder*)code->surface);
228        }
229    }
230}
231
232static void
233onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
234        jint format, jint width, jint height)
235{
236    if (handle != 0) {
237        NativeCode* code = (NativeCode*)handle;
238        if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) {
239            code->callbacks.onSurfaceChanged(&code->activity,
240                    (ASurfaceHolder*)code->surface, format, width, height);
241        }
242    }
243}
244
245static void
246onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
247{
248    if (handle != 0) {
249        NativeCode* code = (NativeCode*)handle;
250        if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) {
251            code->callbacks.onSurfaceDestroyed(&code->activity,
252                    (ASurfaceHolder*)code->surface);
253        }
254        code->setSurface(NULL);
255    }
256}
257
258static void
259onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
260{
261    if (handle != 0) {
262        NativeCode* code = (NativeCode*)handle;
263        status_t err = code->setInputChannel(channel);
264        if (err != OK) {
265            jniThrowException(env, "java/lang/IllegalStateException",
266                    "Error setting input channel");
267            return;
268        }
269        if (code->callbacks.onInputQueueCreated != NULL) {
270            code->callbacks.onInputQueueCreated(&code->activity,
271                    code->nativeInputQueue);
272        }
273    }
274}
275
276static void
277onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
278{
279    if (handle != 0) {
280        NativeCode* code = (NativeCode*)handle;
281        if (code->nativeInputQueue != NULL
282                && code->callbacks.onInputQueueDestroyed != NULL) {
283            code->callbacks.onInputQueueDestroyed(&code->activity,
284                    code->nativeInputQueue);
285        }
286        code->setInputChannel(NULL);
287    }
288}
289
290static const JNINativeMethod g_methods[] = {
291    { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
292    { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
293    { "onStartNative", "(I)V", (void*)onStart_native },
294    { "onResumeNative", "(I)V", (void*)onResume_native },
295    { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native },
296    { "onPauseNative", "(I)V", (void*)onPause_native },
297    { "onStopNative", "(I)V", (void*)onStop_native },
298    { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native },
299    { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
300    { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
301    { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
302    { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
303    { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
304    { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
305};
306
307static const char* const kNativeActivityPathName = "android/app/NativeActivity";
308
309int register_android_app_NativeActivity(JNIEnv* env)
310{
311    //LOGD("register_android_app_NativeActivity");
312
313    jclass clazz;
314
315    clazz = env->FindClass(kNativeActivityPathName);
316    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity");
317
318    return AndroidRuntime::registerNativeMethods(
319        env, kNativeActivityPathName,
320        g_methods, NELEM(g_methods));
321}
322
323} // namespace android
324