From 7d3cefafef0d23d1b858c937c51d836f89cbd3ca Mon Sep 17 00:00:00 2001 From: Mis012 Date: Fri, 4 Nov 2022 19:28:46 +0100 Subject: [PATCH] api-impl: add initial support for NativeAcivity --- meson.build | 3 +- src/api-impl-jni/android_app_NativeActivity.c | 591 ++++++++++++++++++ .../android_app_NativeActivity.h | 149 +++++ src/api-impl-jni/native_activity.h | 313 ++++++++++ .../widgets/android_view_SurfaceView.c | 3 +- src/api-impl/android/app/NativeActivity.java | 340 ++++++++++ src/api-impl/android/view/SurfaceView.java | 52 +- src/api-impl/meson.build | 1 + 8 files changed, 1427 insertions(+), 25 deletions(-) create mode 100644 src/api-impl-jni/android_app_NativeActivity.c create mode 100644 src/api-impl-jni/generated_headers/android_app_NativeActivity.h create mode 100644 src/api-impl-jni/native_activity.h create mode 100644 src/api-impl/android/app/NativeActivity.java diff --git a/meson.build b/meson.build index 0d1b653b..945173f1 100644 --- a/meson.build +++ b/meson.build @@ -44,7 +44,8 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/widgets/android_view_SurfaceView.c', 'src/api-impl-jni/views/android_view_View.c', 'src/api-impl-jni/views/android_view_ViewGroup.c', - 'src/api-impl-jni/android_graphics_Bitmap.c' + 'src/api-impl-jni/android_graphics_Bitmap.c', + 'src/api-impl-jni/android_app_NativeActivity.c', ] + marshal_files, install: true, install_dir : get_option('libdir') / 'java/dex/android_translation_layer/natives', diff --git a/src/api-impl-jni/android_app_NativeActivity.c b/src/api-impl-jni/android_app_NativeActivity.c new file mode 100644 index 00000000..a5b32002 --- /dev/null +++ b/src/api-impl-jni/android_app_NativeActivity.c @@ -0,0 +1,591 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "util.h" + +//#include "generated_headers/android_util_AssetManager.h" +//#include "generated_headers/android_view_Surface.h" + +#include "native_activity.h" +#include "generated_headers/android_app_NativeActivity.h" + +//#include "JNIHelp.h" +//#include "android_os_MessageQueue.h" +//#include "android_view_InputChannel.h" +//#include "android_view_KeyEvent.h" + + +static struct { + jmethodID finish; + jmethodID setWindowFlags; + jmethodID setWindowFormat; + jmethodID showIme; + jmethodID hideIme; +} gNativeActivityClassInfo; + +typedef void ANativeActivity_createFunc(ANativeActivity* activity, void* savedState, size_t savedStateSize); + +// ------------------------------------------------------------------------ + +struct ActivityWork { + int32_t cmd; + int32_t arg1; + int32_t arg2; +}; + +enum { + CMD_FINISH = 1, + CMD_SET_WINDOW_FORMAT, + CMD_SET_WINDOW_FLAGS, + CMD_SHOW_SOFT_INPUT, + CMD_HIDE_SOFT_INPUT, +}; + +static void write_work(int fd, int32_t cmd, int32_t arg1, int32_t arg2) { +/* struct ActivityWork work; + work.cmd = cmd; + work.arg1 = arg1; + work.arg2 = arg2; + + printf("write_work: cmd=%d", cmd); + +restart: + int res = write(fd, &work, sizeof(work)); + if (res < 0 && errno == EINTR) { + goto restart; + } + + if (res == sizeof(work)) return; + + if (res < 0) printf("Failed writing to work fd: %s", strerror(errno)); + else printf("Truncated writing to work fd: %d", res);*/ +} + +static bool read_work(int fd, struct ActivityWork* outWork) { +/* int res = read(fd, outWork, sizeof(struct ActivityWork)); + // no need to worry about EINTR, poll loop will just come back again. + if (res == sizeof(struct ActivityWork)) return true; + + if (res < 0) printf("Failed reading work fd: %s", strerror(errno)); + else printf("Truncated reading work fd: %d", res); +*/ return false; +} + +/* + * Native state for interacting with the NativeActivity class. + */ + +struct NativeCode { + // must have offset of 0 so that our struct acts as a transparent wrapper + struct ANativeActivity native_activity; + + ANativeActivityCallbacks callbacks; + + void* dlhandle; + ANativeActivity_createFunc* createActivityFunc; + +// const char* internalDataPathObj; +// const char* externalDataPathObj; +// const char* obbPathObj; + + ANativeWindow *nativeWindow; + int32_t lastWindowWidth; + int32_t lastWindowHeight; + + // These are used to wake up the main thread to process work. + int mainWorkRead; + int mainWorkWrite; +// MessageQueue *messageQueue; +}; + +struct NativeCode * NativeCode_new(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { + struct NativeCode *this = malloc(sizeof(struct NativeCode)); + memset(&this->callbacks, 0, sizeof(this->callbacks)); + this->dlhandle = _dlhandle; + this->createActivityFunc = _createFunc; + this->nativeWindow = NULL; + this->mainWorkRead = this->mainWorkWrite = -1; + + return this; +} + +// FIXME: this is currently in libandroid.so, which is not necessarily requested by the app and therefore loaded +ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface); + +void NativeCode_setSurface(struct NativeCode *this, jobject _surface) { + if (_surface != NULL) { + this->nativeWindow = ANativeWindow_fromSurface(this->native_activity.env, _surface); + } else { + this->nativeWindow = NULL; + } +} + +void NativeCode_destroy(struct NativeCode *this) { + if (this->callbacks.onDestroy != NULL) { + this->callbacks.onDestroy((struct ANativeActivity *)this); + } +// if (env != NULL && clazz != NULL) { +// (*env)->DeleteGlobalRef(env, clazz); +// } +// if (messageQueue != NULL && mainWorkRead >= 0) { +// messageQueue->getLooper()->removeFd(mainWorkRead); +// } + NativeCode_setSurface(this, NULL); + if (this->mainWorkRead >= 0) close(this->mainWorkRead); + if (this->mainWorkWrite >= 0) close(this->mainWorkWrite); + if (this->dlhandle != NULL) { + // for now don't unload... we probably should clean this + // up and only keep one open dlhandle per proc, since there + // is really no benefit to unloading the code. + //dlclose(this->dlhandle); + } + free(this); +} + + +// ------------------------------------------------------------------------ + +/* + * Callback for handling native events on the application's main thread. + */ +static int mainWorkCallback(int fd, int events, void* data) { + struct NativeCode* code = (struct NativeCode*)data; + if ((events & POLLIN) == 0) { + printf("STUB - mainWorkCallback - returning -1\n"); + return 1; + } + +/* struct ActivityWork work; + if (!read_work(code->mainWorkRead, &work)) { + return 1; + }*/ + + printf("STUB - mainWorkCallback\n"); +// printf("mainWorkCallback: cmd=%d", work.cmd); + +/* switch (work.cmd) { + case CMD_FINISH: { + code->(*env)->CallVoidMethod(env, code->clazz, gNativeActivityClassInfo.finish); + code->messageQueue->raiseAndClearException(code->env, "finish"); + } break; + case CMD_SET_WINDOW_FORMAT: { + code->(*env)->CallVoidMethod(env, code->clazz, + gNativeActivityClassInfo.setWindowFormat, work.arg1); + code->messageQueue->raiseAndClearException(code->env, "setWindowFormat"); + } break; + case CMD_SET_WINDOW_FLAGS: { + code->(*env)->CallVoidMethod(env, code->clazz, + gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2); + code->messageQueue->raiseAndClearException(code->env, "setWindowFlags"); + } break; + case CMD_SHOW_SOFT_INPUT: { + code->(*env)->CallVoidMethod(env, code->clazz, + gNativeActivityClassInfo.showIme, work.arg1); + code->messageQueue->raiseAndClearException(code->env, "showIme"); + } break; + case CMD_HIDE_SOFT_INPUT: { + code->(*env)->CallVoidMethod(env, code->clazz, + gNativeActivityClassInfo.hideIme, work.arg1); + code->messageQueue->raiseAndClearException(code->env, "hideIme"); + } break; + default: + printf("Unknown work command: %d", work.cmd); + break; + }*/ + + return 1; +} + +// ------------------------------------------------------------------------ + +void *bionic_dlopen(const char *filename, int flag); +void *bionic_dlsym(void *handle, const char *symbol); + +// constructor: android::Looper::Looper(bool) +void _ZN7android6LooperC2Eb(void *dest, bool allowNonCallbacks); +typedef int (*Looper_callbackFunc)(int fd, int events, void* data); +// android::Looper::addFd +int _ZN7android6Looper5addFdEiiiPFiiiPvES1_(void *this, int fd, int ident, int events, Looper_callbackFunc callback, void* data); +// android::Looper::pollOnce +int _ZN7android6Looper8pollOnceEiPiS1_PPv(void *this, int timeoutMillis, int* outFd, int* outEvents, void** outData); +#define ALOOPER_EVENT_INPUT (1 << 0) + +/*static pthread_t looper_thread; + +static void * looper_thread_worker(void *looper) +{ + printf("!!!!! in looper_thread_worker\n"); + _ZN7android6Looper8pollOnceEiPiS1_PPv(looper, -1, NULL, NULL, NULL); + printf("!!!!! pollOnce returned\n"); +}*/ + +jlong +Java_android_app_NativeActivity_loadNativeCode(JNIEnv* env, jobject clazz, jstring path, jstring funcName, + jobject messageQueue, jstring internalDataDir, jstring obbDir, + jstring externalDataDir, int sdkVersion, + jobject jAssetMgr, jbyteArray savedState) +{ + printf("STUB - loadNativeCode_native\n"); + + const char* pathStr = (*env)->GetStringUTFChars(env, path, NULL); + struct NativeCode* code = NULL; + + void* handle = bionic_dlopen(pathStr, RTLD_LAZY); + + (*env)->ReleaseStringUTFChars(env, path, pathStr); + + if (handle != NULL) { + const char* funcStr = (*env)->GetStringUTFChars(env, funcName, NULL); + code = NativeCode_new(handle, (ANativeActivity_createFunc*) + bionic_dlsym(handle, funcStr)); + (*env)->ReleaseStringUTFChars(env, funcName, funcStr); + + if (code->createActivityFunc == NULL) { + printf("ANativeActivity_onCreate not found\n"); + NativeCode_destroy(code); + return 0; + } +/* + code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue); + if (code->messageQueue == NULL) { + printf("Unable to retrieve native MessageQueue\n"); + NativeCode_destroy(code); + return 0; + } +*/ + int msgpipe[2]; + if (pipe(msgpipe)) { + printf("could not create pipe: %s", strerror(errno)); + NativeCode_destroy(code); + return 0; + } + code->mainWorkRead = msgpipe[0]; + code->mainWorkWrite = msgpipe[1]; + int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); +// SLOGW_IF(result != 0, "Could not make main work read pipe " +// "non-blocking: %s", strerror(errno)); + result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); +// SLOGW_IF(result != 0, "Could not make main work write pipe " +// "non-blocking: %s", strerror(errno)); +// code->messageQueue->getLooper()->addFd( +// code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); + + // new android::Looper() +#if 0 + void *a_looper = malloc(224/*sizeof(android::Looper)*/); + _ZN7android6LooperC2Eb(a_looper, true); // TODO: or false? + // android::Looper::addFd + _ZN7android6Looper5addFdEiiiPFiiiPvES1_(a_looper, code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); + pthread_create(&looper_thread, NULL, looper_thread_worker, a_looper); +#endif + code->native_activity.callbacks = &code->callbacks; + if ((*env)->GetJavaVM(env, &code->native_activity.vm) < 0) { + printf("NativeActivity GetJavaVM failed\n"); + NativeCode_destroy(code); + return 0; + } + code->native_activity.env = env; + code->native_activity.clazz = (*env)->NewGlobalRef(env, clazz); + + code->native_activity.internalDataPath = (*env)->GetStringUTFChars(env, internalDataDir, NULL); + (*env)->ReleaseStringUTFChars(env, internalDataDir, code->native_activity.internalDataPath); + + if (externalDataDir != NULL) { + code->native_activity.externalDataPath = (*env)->GetStringUTFChars(env, externalDataDir, NULL); + (*env)->ReleaseStringUTFChars(env, externalDataDir, code->native_activity.externalDataPath); + } else { + code->native_activity.externalDataPath = NULL; // TODO: or ""? + } + + code->native_activity.sdkVersion = sdkVersion; + + code->native_activity.assetManager = NULL;//assetManagerForJavaObject(env, jAssetMgr); + + if (obbDir != NULL) { + code->native_activity.obbPath = (*env)->GetStringUTFChars(env, obbDir, NULL); + (*env)->ReleaseStringUTFChars(env, obbDir, code->native_activity.obbPath); + } else { + code->native_activity.obbPath = NULL; // TODO: or ""? + } + + jbyte* rawSavedState = NULL; + jsize rawSavedSize = 0; + if (savedState != NULL) { + rawSavedState = (*env)->GetByteArrayElements(env, savedState, NULL); + rawSavedSize = (*env)->GetArrayLength(env, savedState); + } + + code->createActivityFunc((struct ANativeActivity *)code, rawSavedState, rawSavedSize); + + if (rawSavedState != NULL) { + (*env)->ReleaseByteArrayElements(env, savedState, rawSavedState, 0); + } + } + + return (jlong)code; // sus, surely this is broken on 64bit? +} + +void +Java_android_app_NativeActivity_unloadNativeCode(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - unloadNativeCode_native\n"); + /*if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + NativeCode_destroy(code); + }*/ +} + +void +Java_android_app_NativeActivity_onStartNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onStart_native\n"); + if (handle != 0) { + struct NativeCode* code = (struct NativeCode*)handle; + if (code->callbacks.onStart != NULL) { + code->callbacks.onStart(code); + } + } +} + +void +Java_android_app_NativeActivity_onResumeNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onResume_native\n"); + if (handle != 0) { + struct NativeCode* code = (struct NativeCode*)handle; + if (code->callbacks.onResume != NULL) { + code->callbacks.onResume(code); + } + } +} + +jbyteArray +Java_android_app_NativeActivity_onSaveInstanceStateNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onSaveInstanceState_native\n"); +/* + jbyteArray array = NULL; + + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onSaveInstanceState != NULL) { + size_t len = 0; + jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len); + if (len > 0) { + array = (*env)->NewByteArray(env, len); + if (array != NULL) { + (*env)->SetByteArrayRegion(env, array, 0, len, state); + } + } + if (state != NULL) { + free(state); + } + } + } + + return array;*/return NULL; +} + +void +Java_android_app_NativeActivity_onPauseNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onPause_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onPause != NULL) { + code->callbacks.onPause(code); + } + }*/ +} + +void +Java_android_app_NativeActivity_onStopNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onStop_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStop != NULL) { + code->callbacks.onStop(code); + } + }*/ +} + +void +Java_android_app_NativeActivity_onConfigurationChangedNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onConfigurationChanged_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onConfigurationChanged != NULL) { + code->callbacks.onConfigurationChanged(code); + } + }*/ +} + +void +Java_android_app_NativeActivity_onLowMemoryNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onLowMemory_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onLowMemory != NULL) { + code->callbacks.onLowMemory(code); + } + }*/ +} + +void +Java_android_app_NativeActivity_onWindowFocusChangedNative(JNIEnv* env, jobject clazz, jlong handle, jboolean focused) +{ + printf("STUB - onWindowFocusChanged_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onWindowFocusChanged != NULL) { + code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); + } + }*/ +} + +void +Java_android_app_NativeActivity_onSurfaceCreatedNative(JNIEnv* env, jobject clazz, jlong handle, jobject surface) +{ + printf("STUB - onSurfaceCreated_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + code->setSurface(surface); + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) { + code->callbacks.onNativeWindowCreated(code, + code->nativeWindow.get()); + } + }*/ +} + +void +Java_android_app_NativeActivity_onSurfaceChangedNative(JNIEnv* env, jobject clazz, jlong handle, jobject surface, + jint format, jint width, jint height) +{ + printf("STUB - onSurfaceChanged_native\n"); + if (handle != 0) { + struct NativeCode *code = (struct NativeCode *)handle; + ANativeWindow *oldNativeWindow = code->nativeWindow; + NativeCode_setSurface(code, surface); + if (oldNativeWindow != code->nativeWindow) { + if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { + code->callbacks.onNativeWindowDestroyed(code, + oldNativeWindow); + } + if (code->nativeWindow != NULL) { + if (code->callbacks.onNativeWindowCreated != NULL) { + code->callbacks.onNativeWindowCreated(code, + code->nativeWindow); + } + code->lastWindowWidth = width; + code->lastWindowHeight = height; + } + } else { + // Maybe it resized? + if (width != code->lastWindowWidth + || height != code->lastWindowHeight) { + if (code->callbacks.onNativeWindowResized != NULL) { + code->callbacks.onNativeWindowResized(code, + code->nativeWindow); + } + } + } + } +} + +void +Java_android_app_NativeActivity_onSurfaceRedrawNeededNative(JNIEnv* env, jobject clazz, jlong handle, jobject surface/*?*/) +{ + printf("STUB - onSurfaceRedrawNeeded_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) { + code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get()); + } + }*/ +} + +void +Java_android_app_NativeActivity_onSurfaceDestroyedNative(JNIEnv* env, jobject clazz, jlong handle) +{ + printf("STUB - onSurfaceDestroyed_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { + code->callbacks.onNativeWindowDestroyed(code, + code->nativeWindow.get()); + } + code->setSurface(NULL); + }*/ +} + +void +Java_android_app_NativeActivity_onInputQueueCreatedNative(JNIEnv* env, jobject clazz, jlong handle, jint queuePtr) +{ + printf("STUB - onInputChannelCreated_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onInputQueueCreated != NULL) { + AInputQueue* queue = reinterpret_cast(queuePtr); + code->callbacks.onInputQueueCreated(code, queue); + } + }*/ +} + +void +Java_android_app_NativeActivity_onInputQueueDestroyedNative(JNIEnv* env, jobject clazz, jlong handle, jint queuePtr) +{ + printf("STUB - onInputChannelDestroyed_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onInputQueueDestroyed != NULL) { + AInputQueue* queue = reinterpret_cast(queuePtr); + code->callbacks.onInputQueueDestroyed(code, queue); + } + }*/ +} + +void +Java_android_app_NativeActivity_onContentRectChangedNative(JNIEnv* env, jobject clazz, jlong handle, + jint x, jint y, jint w, jint h) +{ + printf("STUB - onContentRectChanged_native\n"); +/* if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onContentRectChanged != NULL) { + ARect rect; + rect.left = x; + rect.top = y; + rect.right = x+w; + rect.bottom = y+h; + code->callbacks.onContentRectChanged(code, &rect); + } + }*/ +} diff --git a/src/api-impl-jni/generated_headers/android_app_NativeActivity.h b/src/api-impl-jni/generated_headers/android_app_NativeActivity.h new file mode 100644 index 00000000..8b2115e4 --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_app_NativeActivity.h @@ -0,0 +1,149 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_app_NativeActivity */ + +#ifndef _Included_android_app_NativeActivity +#define _Included_android_app_NativeActivity +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: android_app_NativeActivity + * Method: loadNativeCode + * Signature: (Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)J + */ +JNIEXPORT jlong JNICALL Java_android_app_NativeActivity_loadNativeCode + (JNIEnv *, jobject, jstring, jstring, jobject, jstring, jstring, jstring, jint, jobject, jbyteArray); + +/* + * Class: android_app_NativeActivity + * Method: unloadNativeCode + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_unloadNativeCode + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onStartNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onStartNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onResumeNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onResumeNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onSaveInstanceStateNative + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL Java_android_app_NativeActivity_onSaveInstanceStateNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onPauseNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onPauseNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onStopNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onStopNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onConfigurationChangedNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onConfigurationChangedNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onLowMemoryNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onLowMemoryNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onWindowFocusChangedNative + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onWindowFocusChangedNative + (JNIEnv *, jobject, jlong, jboolean); + +/* + * Class: android_app_NativeActivity + * Method: onSurfaceCreatedNative + * Signature: (JLandroid/view/Surface;)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onSurfaceCreatedNative + (JNIEnv *, jobject, jlong, jobject); + +/* + * Class: android_app_NativeActivity + * Method: onSurfaceChangedNative + * Signature: (JLandroid/view/Surface;III)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onSurfaceChangedNative + (JNIEnv *, jobject, jlong, jobject, jint, jint, jint); + +/* + * Class: android_app_NativeActivity + * Method: onSurfaceRedrawNeededNative + * Signature: (JLandroid/view/Surface;)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onSurfaceRedrawNeededNative + (JNIEnv *, jobject, jlong, jobject); + +/* + * Class: android_app_NativeActivity + * Method: onSurfaceDestroyedNative + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onSurfaceDestroyedNative + (JNIEnv *, jobject, jlong); + +/* + * Class: android_app_NativeActivity + * Method: onInputQueueCreatedNative + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onInputQueueCreatedNative + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: android_app_NativeActivity + * Method: onInputQueueDestroyedNative + * Signature: (JI)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onInputQueueDestroyedNative + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: android_app_NativeActivity + * Method: onContentRectChangedNative + * Signature: (JIIII)V + */ +JNIEXPORT void JNICALL Java_android_app_NativeActivity_onContentRectChangedNative + (JNIEnv *, jobject, jlong, jint, jint, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/native_activity.h b/src/api-impl-jni/native_activity.h new file mode 100644 index 00000000..2d7d08a9 --- /dev/null +++ b/src/api-impl-jni/native_activity.h @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_NATIVE_ACTIVITY_H +#define ANDROID_NATIVE_ACTIVITY_H + +#include +#include + +#include + +//#include +//#include +//#include +typedef void ANativeWindow; +typedef void AInputQueue; +typedef void ARect; + +#ifdef __cplusplus +extern "C" { +#endif + +struct ANativeActivityCallbacks; + +/** + * This structure defines the native side of an android.app.NativeActivity. + * It is created by the framework, and handed to the application's native + * code as it is being launched. + */ +typedef struct ANativeActivity { + /** + * Pointer to the callback function table of the native application. + * You can set the functions here to your own callbacks. The callbacks + * pointer itself here should not be changed; it is allocated and managed + * for you by the framework. + */ + struct ANativeActivityCallbacks* callbacks; + + /** + * The global handle on the process's Java VM. + */ + JavaVM* vm; + + /** + * JNI context for the main thread of the app. Note that this field + * can ONLY be used from the main thread of the process; that is, the + * thread that calls into the ANativeActivityCallbacks. + */ + JNIEnv* env; + + /** + * The NativeActivity object handle. + * + * IMPORTANT NOTE: This member is mis-named. It should really be named + * 'activity' instead of 'clazz', since it's a reference to the + * NativeActivity instance created by the system for you. + * + * We unfortunately cannot change this without breaking NDK + * source-compatibility. + */ + jobject clazz; + + /** + * Path to this application's internal data directory. + */ + const char* internalDataPath; + + /** + * Path to this application's external (removable/mountable) data directory. + */ + const char* externalDataPath; + + /** + * The platform's SDK version code. + */ + int32_t sdkVersion; + + /** + * This is the native instance of the application. It is not used by + * the framework, but can be set by the application to its own instance + * state. + */ + void* instance; + + /** + * Pointer to the Asset Manager instance for the application. The application + * uses this to access binary assets bundled inside its own .apk file. + */ + /*AAssetManager*/void* assetManager; + + /** + * Available starting with Honeycomb: path to the directory containing + * the application's OBB files (if any). If the app doesn't have any + * OBB files, this directory may not exist. + */ + const char* obbPath; +} ANativeActivity; + +/** + * These are the callbacks the framework makes into a native application. + * All of these callbacks happen on the main thread of the application. + * By default, all callbacks are NULL; set to a pointer to your own function + * to have it called. + */ +typedef struct ANativeActivityCallbacks { + /** + * NativeActivity has started. See Java documentation for Activity.onStart() + * for more information. + */ + void (*onStart)(ANativeActivity* activity); + + /** + * NativeActivity has resumed. See Java documentation for Activity.onResume() + * for more information. + */ + void (*onResume)(ANativeActivity* activity); + + /** + * Framework is asking NativeActivity to save its current instance state. + * See Java documentation for Activity.onSaveInstanceState() for more + * information. The returned pointer needs to be created with malloc(); + * the framework will call free() on it for you. You also must fill in + * outSize with the number of bytes in the allocation. Note that the + * saved state will be persisted, so it can not contain any active + * entities (pointers to memory, file descriptors, etc). + */ + void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize); + + /** + * NativeActivity has paused. See Java documentation for Activity.onPause() + * for more information. + */ + void (*onPause)(ANativeActivity* activity); + + /** + * NativeActivity has stopped. See Java documentation for Activity.onStop() + * for more information. + */ + void (*onStop)(ANativeActivity* activity); + + /** + * NativeActivity is being destroyed. See Java documentation for Activity.onDestroy() + * for more information. + */ + void (*onDestroy)(ANativeActivity* activity); + + /** + * Focus has changed in this NativeActivity's window. This is often used, + * for example, to pause a game when it loses input focus. + */ + void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus); + + /** + * The drawing window for this native activity has been created. You + * can use the given native window object to start drawing. + */ + void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity has been resized. You should + * retrieve the new size from the window and ensure that your rendering in + * it now matches. + */ + void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity needs to be redrawn. To avoid + * transient artifacts during screen changes (such resizing after rotation), + * applications should not return from this function until they have finished + * drawing their window in its current state. + */ + void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window); + + /** + * The drawing window for this native activity is going to be destroyed. + * You MUST ensure that you do not touch the window object after returning + * from this function: in the common case of drawing to the window from + * another thread, that means the implementation of this callback must + * properly synchronize with the other thread to stop its drawing before + * returning from here. + */ + void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window); + + /** + * The input queue for this native activity's window has been created. + * You can use the given input queue to start retrieving input events. + */ + void (*onInputQueueCreated)(ANativeActivity* activity, AInputQueue* queue); + + /** + * The input queue for this native activity's window is being destroyed. + * You should no longer try to reference this object upon returning from this + * function. + */ + void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue); + + /** + * The rectangle in the window in which content should be placed has changed. + */ + void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect); + + /** + * The current device AConfiguration has changed. The new configuration can + * be retrieved from assetManager. + */ + void (*onConfigurationChanged)(ANativeActivity* activity); + + /** + * The system is running low on memory. Use this callback to release + * resources you do not need, to help the system avoid killing more + * important processes. + */ + void (*onLowMemory)(ANativeActivity* activity); +} ANativeActivityCallbacks; + +/** + * This is the function that must be in the native code to instantiate the + * application's native activity. It is called with the activity instance (see + * above); if the code is being instantiated from a previously saved instance, + * the savedState will be non-NULL and point to the saved data. You must make + * any copy of this data you need -- it will be released after you return from + * this function. + */ +typedef void ANativeActivity_createFunc(ANativeActivity* activity, + void* savedState, size_t savedStateSize); + +/** + * The name of the function that NativeInstance looks for when launching its + * native code. This is the default function that is used, you can specify + * "android.app.func_name" string meta-data in your manifest to use a different + * function. + */ +extern ANativeActivity_createFunc ANativeActivity_onCreate; + +/** + * Finish the given activity. Its finish() method will be called, causing it + * to be stopped and destroyed. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ +void ANativeActivity_finish(ANativeActivity* activity); + +/** + * Change the window format of the given activity. Calls getWindow().setFormat() + * of the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ +void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); + +/** + * Change the window flags of the given activity. Calls getWindow().setFlags() + * of the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. See window.h for flag constants. + */ +void ANativeActivity_setWindowFlags(ANativeActivity* activity, + uint32_t addFlags, uint32_t removeFlags); + +/** + * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager + * API for documentation. + */ +enum { + ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, + ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, +}; + +/** + * Show the IME while in the given activity. Calls InputMethodManager.showSoftInput() + * for the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ +void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags); + +/** + * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager + * API for documentation. + */ +enum { + ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, + ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, +}; + +/** + * Hide the IME while in the given activity. Calls InputMethodManager.hideSoftInput() + * for the given activity. Note that this method can be called from + * *any* thread; it will send a message to the main thread of the process + * where the Java finish call will take place. + */ +void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_ACTIVITY_H + diff --git a/src/api-impl-jni/widgets/android_view_SurfaceView.c b/src/api-impl-jni/widgets/android_view_SurfaceView.c index d89919c9..c9529a1d 100644 --- a/src/api-impl-jni/widgets/android_view_SurfaceView.c +++ b/src/api-impl-jni/widgets/android_view_SurfaceView.c @@ -77,6 +77,7 @@ static void on_resize(GtkWidget* self, gint width, gint height, struct jni_callb (*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6); // TODO: are there cases where returning RGBA_8888 is a bad idea? + // NOTE: we want to call the private method of android.view.SurfaceView, not the related method with this name in the API (*env)->CallVoidMethod(env, d->this, _METHOD(d->this_class, "surfaceChanged", "(Landroid/view/SurfaceHolder;III)V"), _GET_OBJ_FIELD(d->this, "mSurfaceHolder", "Landroid/view/SurfaceHolder;"), 1 /*RGBA_8888*/, width, height); @@ -98,7 +99,7 @@ JNIEXPORT void JNICALL Java_android_view_SurfaceView_native_1constructor(JNIEnv struct jni_callback_data *callback_data = malloc(sizeof(struct jni_callback_data)); callback_data->jvm = jvm; callback_data->this = _REF(this); - callback_data->this_class = _REF(_CLASS(this)); + callback_data->this_class = _REF((*env)->FindClass(env, "android/view/SurfaceView")); g_signal_connect(dummy, "resize", G_CALLBACK(on_resize), callback_data); diff --git a/src/api-impl/android/app/NativeActivity.java b/src/api-impl/android/app/NativeActivity.java new file mode 100644 index 00000000..f217ed1b --- /dev/null +++ b/src/api-impl/android/app/NativeActivity.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.res.Configuration; +//import android.graphics.PixelFormat; +import android.os.Build; +import android.os.Bundle; +import android.os.Looper; +import android.os.MessageQueue; +import android.util.AttributeSet; +//import android.view.InputQueue; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.view.WindowManager; +//import android.view.inputmethod.InputMethodManager; + +import java.io.File; + +/** + * Convenience for implementing an activity that will be implemented + * purely in native code. That is, a game (or game-like thing). There + * is no need to derive from this class; you can simply declare it in your + * manifest, and use the NDK APIs from there. + * + *

A typical manifest would look like: + * + * {@sample development/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml + * manifest} + * + *

A very simple example of native code that is run by NativeActivity + * follows. This reads input events from the user and uses OpenGLES to + * draw into the native activity's window. + * + * {@sample development/ndk/platforms/android-9/samples/native-activity/jni/main.c all} + */ +public class NativeActivity extends Activity implements SurfaceHolder.Callback, + /*InputQueue.Callback, */OnGlobalLayoutListener { + /** + * Optional meta-that can be in the manifest for this component, specifying + * the name of the native shared library to load. If not specified, + * "main" is used. + */ + public static final String META_DATA_LIB_NAME = "android.app.lib_name"; + + /** + * Optional meta-that can be in the manifest for this component, specifying + * the name of the main entry point for this native activity in the + * {@link #META_DATA_LIB_NAME} native code. If not specified, + * "ANativeActivity_onCreate" is used. + */ + public static final String META_DATA_FUNC_NAME = "android.app.func_name"; + + private static final String KEY_NATIVE_SAVED_STATE = "android:native_state"; + + private NativeContentView mNativeContentView; +// private InputMethodManager mIMM; + + private long mNativeHandle; + +// private InputQueue mCurInputQueue; + private SurfaceHolder mCurSurfaceHolder; + + final int[] mLocation = new int[2]; + int mLastContentX; + int mLastContentY; + int mLastContentWidth; + int mLastContentHeight; + + private boolean mDispatchingUnhandledKey; + + private boolean mDestroyed; + + private native long loadNativeCode(String path, String funcname, MessageQueue queue, + String internalDataPath, String obbPath, String externalDataPath, int sdkVersion, + AssetManager assetMgr, byte[] savedState); + private native void unloadNativeCode(long handle); + + private native void onStartNative(long handle); + private native void onResumeNative(long handle); + private native byte[] onSaveInstanceStateNative(long handle); + private native void onPauseNative(long handle); + private native void onStopNative(long handle); + private native void onConfigurationChangedNative(long handle); + private native void onLowMemoryNative(long handle); + private native void onWindowFocusChangedNative(long handle, boolean focused); + private native void onSurfaceCreatedNative(long handle, Surface surface); + private native void onSurfaceChangedNative(long handle, Surface surface, + int format, int width, int height); + private native void onSurfaceRedrawNeededNative(long handle, Surface surface); + private native void onSurfaceDestroyedNative(long handle); + private native void onInputQueueCreatedNative(long handle, int queuePtr); + private native void onInputQueueDestroyedNative(long handle, int queuePtr); + private native void onContentRectChangedNative(long handle, int x, int y, int w, int h); + + static class NativeContentView extends SurfaceView { + NativeActivity mActivity; + + public NativeContentView(Context context) { + super(context); + } + + public NativeContentView(Context context, AttributeSet attrs) { + super(context/*, attrs*/); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + String libname = "main"; + String funcname = "ANativeActivity_onCreate"; + ActivityInfo ai; + +// mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + +// getWindow().takeSurface(this); +// getWindow().takeInputQueue(this); +// getWindow().setFormat(PixelFormat.RGB_565); +// getWindow().setSoftInputMode( +// WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED +// | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + + mNativeContentView = new NativeContentView(this); + mNativeContentView.mActivity = this; + mNativeContentView.getHolder().addCallback(this); + setContentView(mNativeContentView); + mNativeContentView.requestFocus(); + mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this); + +/* try { + ai = getPackageManager().getActivityInfo( + getIntent().getComponent(), PackageManager.GET_META_DATA); + if (ai.metaData != null) { + String ln = ai.metaData.getString(META_DATA_LIB_NAME); + if (ln != null) libname = ln; + ln = ai.metaData.getString(META_DATA_FUNC_NAME); + if (ln != null) funcname = ln; + } + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException("Error getting activity info", e); + }*/ + + String path = null; + + File libraryFile = new File(new File(android.os.Environment.getExternalStorageDirectory(), "lib"), + System.mapLibraryName(libname)); + if (libraryFile.exists()) { + path = libraryFile.getPath(); + } + + if (path == null) { + throw new IllegalArgumentException("Unable to find native library: " + libname); + } + + byte[] nativeSavedState = savedInstanceState != null + ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; + + mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(), + getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()), + getAbsolutePath(getExternalFilesDir(null)), + Build.VERSION.SDK_INT, getAssets(), nativeSavedState); + + if (mNativeHandle == 0) { + throw new IllegalArgumentException("Unable to load native library: " + path); + } + super.onCreate(savedInstanceState); + } + + private static String getAbsolutePath(File file) { + return (file != null) ? file.getAbsolutePath() : null; + } + + @Override + protected void onDestroy() { + mDestroyed = true; + if (mCurSurfaceHolder != null) { + onSurfaceDestroyedNative(mNativeHandle); + mCurSurfaceHolder = null; + } +/* if (mCurInputQueue != null) { + onInputQueueDestroyedNative(mNativeHandle, mCurInputQueue.getNativePtr()); + mCurInputQueue = null; + }*/ + unloadNativeCode(mNativeHandle); + super.onDestroy(); + } + + @Override + protected void onPause() { + super.onPause(); + onPauseNative(mNativeHandle); + } + + @Override + protected void onResume() { + super.onResume(); + onResumeNative(mNativeHandle); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + byte[] state = onSaveInstanceStateNative(mNativeHandle); + if (state != null) { + outState.putByteArray(KEY_NATIVE_SAVED_STATE, state); + } + } + + @Override + protected void onStart() { + super.onStart(); + onStartNative(mNativeHandle); + } + + @Override + protected void onStop() { + super.onStop(); + onStopNative(mNativeHandle); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (!mDestroyed) { + onConfigurationChangedNative(mNativeHandle); + } + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + if (!mDestroyed) { + onLowMemoryNative(mNativeHandle); + } + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (!mDestroyed) { + onWindowFocusChangedNative(mNativeHandle, hasFocus); + } + } + + public void surfaceCreated(SurfaceHolder holder) { + if (!mDestroyed) { + mCurSurfaceHolder = holder; + onSurfaceCreatedNative(mNativeHandle, holder.getSurface()); + } + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (!mDestroyed) { + mCurSurfaceHolder = holder; + onSurfaceChangedNative(mNativeHandle, holder.getSurface(), format, width, height); + } + } + + public void surfaceRedrawNeeded(SurfaceHolder holder) { + if (!mDestroyed) { + mCurSurfaceHolder = holder; + onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface()); + } + } + + public void surfaceDestroyed(SurfaceHolder holder) { + mCurSurfaceHolder = null; + if (!mDestroyed) { + onSurfaceDestroyedNative(mNativeHandle); + } + } + +/* public void onInputQueueCreated(InputQueue queue) { + if (!mDestroyed) { + mCurInputQueue = queue; + onInputQueueCreatedNative(mNativeHandle, queue.getNativePtr()); + } + }*/ + +/* public void onInputQueueDestroyed(InputQueue queue) { + if (!mDestroyed) { + onInputQueueDestroyedNative(mNativeHandle, queue.getNativePtr()); + mCurInputQueue = null; + } + }*/ + + public void onGlobalLayout() { +/* mNativeContentView.getLocationInWindow(mLocation); + int w = mNativeContentView.getWidth(); + int h = mNativeContentView.getHeight(); + if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY + || w != mLastContentWidth || h != mLastContentHeight) { + mLastContentX = mLocation[0]; + mLastContentY = mLocation[1]; + mLastContentWidth = w; + mLastContentHeight = h; + if (!mDestroyed) { + onContentRectChangedNative(mNativeHandle, mLastContentX, + mLastContentY, mLastContentWidth, mLastContentHeight); + } + }*/ + } + + void setWindowFlags(int flags, int mask) { +// getWindow().setFlags(flags, mask); + } + + void setWindowFormat(int format) { +// getWindow().setFormat(format); + } + + void showIme(int mode) { +// mIMM.showSoftInput(mNativeContentView, mode); + } + + void hideIme(int mode) { +// mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode); + } +} diff --git a/src/api-impl/android/view/SurfaceView.java b/src/api-impl/android/view/SurfaceView.java index 401eabf5..ca5824de 100644 --- a/src/api-impl/android/view/SurfaceView.java +++ b/src/api-impl/android/view/SurfaceView.java @@ -5,8 +5,12 @@ import android.graphics.Rect; import android.content.Context; +import java.util.ArrayList; + public class SurfaceView extends View { + final ArrayList mCallbacks = new ArrayList(); + public SurfaceView(Context context) { super(context); @@ -15,13 +19,17 @@ public class SurfaceView extends View { mSurface.widget = this.widget; } + private void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + for (SurfaceHolder.Callback c : mCallbacks) { + c.surfaceChanged(mSurfaceHolder, format, width, height); + } + } + private native void native_constructor(Context context); - public SurfaceHolder getHolder() { + public SurfaceHolder getHolder() { return mSurfaceHolder; - } - - void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {} + } final Surface mSurface = new Surface(); @@ -30,31 +38,29 @@ public class SurfaceView extends View { @Override public boolean isCreating() { - // return mIsCreating; + // return mIsCreating; return false; } @Override public void addCallback(Callback callback) { - /* synchronized (mCallbacks) { - // This is a linear search, but in practice we'll - // have only a couple callbacks, so it doesn't matter. - if (mCallbacks.contains(callback) == false) { - mCallbacks.add(callback); + synchronized (mCallbacks) { + if (mCallbacks.contains(callback) == false) { + mCallbacks.add(callback); + } } - }*/ } @Override public void removeCallback(Callback callback) { - /* synchronized (mCallbacks) { + /* synchronized (mCallbacks) { mCallbacks.remove(callback); }*/ } @Override public void setFixedSize(int width, int height) { - /* if (mRequestedWidth != width || mRequestedHeight != height) { + /* if (mRequestedWidth != width || mRequestedHeight != height) { mRequestedWidth = width; mRequestedHeight = height; requestLayout(); @@ -63,7 +69,7 @@ public class SurfaceView extends View { @Override public void setSizeFromLayout() { - /* if (mRequestedWidth != -1 || mRequestedHeight != -1) { + /* if (mRequestedWidth != -1 || mRequestedHeight != -1) { mRequestedWidth = mRequestedHeight = -1; requestLayout(); }*/ @@ -92,9 +98,9 @@ public class SurfaceView extends View { @Override public void setKeepScreenOn(boolean screenOn) { - // Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG); - // msg.arg1 = screenOn ? 1 : 0; - // mHandler.sendMessage(msg); + // Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG); + // msg.arg1 = screenOn ? 1 : 0; + // mHandler.sendMessage(msg); } /** @@ -108,7 +114,7 @@ public class SurfaceView extends View { */ @Override public Canvas lockCanvas() { - // return internalLockCanvas(null); + // return internalLockCanvas(null); return null; } @@ -129,12 +135,12 @@ public class SurfaceView extends View { */ @Override public Canvas lockCanvas(Rect inOutDirty) { - // return internalLockCanvas(inOutDirty); + // return internalLockCanvas(inOutDirty); return null; } private final Canvas internalLockCanvas(Rect dirty) { - /* mSurfaceLock.lock(); + /* mSurfaceLock.lock(); if (DEBUG) Log.i(TAG, "Locking canvas... stopped=" + mDrawingStopped + ", win=" + mWindow); @@ -180,8 +186,8 @@ public class SurfaceView extends View { */ @Override public void unlockCanvasAndPost(Canvas canvas) { - // mSurface.unlockCanvasAndPost(canvas); - // mSurfaceLock.unlock(); + // mSurface.unlockCanvasAndPost(canvas); + // mSurfaceLock.unlock(); } @Override @@ -191,7 +197,7 @@ public class SurfaceView extends View { @Override public Rect getSurfaceFrame() { - // return mSurfaceFrame; + // return mSurfaceFrame; return null; } }; diff --git a/src/api-impl/meson.build b/src/api-impl/meson.build index 93bfcc1b..20ad92e5 100644 --- a/src/api-impl/meson.build +++ b/src/api-impl/meson.build @@ -11,6 +11,7 @@ hax_jar = jar('hax', [ 'android/app/Dialog.java', 'android/app/IntentService.java', 'android/app/KeyguardManager.java', + 'android/app/NativeActivity.java', 'android/app/PendingIntent.java', 'android/app/ProgressDialog.java', 'android/app/Service.java',