diff -r f8588afb6486 android-project/default.properties --- a/android-project/default.properties Mon Feb 28 23:50:32 2011 -0800 +++ b/android-project/default.properties Thu Mar 03 12:25:33 2011 +0100 @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-4 +target=android-7 diff -r f8588afb6486 android-project/src/org/libsdl/app/SDLActivity.java --- a/android-project/src/org/libsdl/app/SDLActivity.java Mon Feb 28 23:50:32 2011 -0800 +++ b/android-project/src/org/libsdl/app/SDLActivity.java Thu Mar 03 12:25:33 2011 +0100 @@ -95,6 +95,8 @@ public static native void onNativeKeyUp(int keycode); public static native void onNativeTouch(int action, float x, float y, float p); + public static native void onNativeMultiTouch(int action, float x, + float y, int pointerId, float pressure); public static native void onNativeAccel(float x, float y, float z); public static native void nativeRunAudioThread(); @@ -244,6 +246,21 @@ // Sensors private static SensorManager mSensorManager; + private static final int touchEventMax = 16; // Max multitouch pointers + private static touchEvent touchEvents[]; + private static boolean multiTouch = true; + private static class touchEvent + { + public boolean down = false; + public float x = 0; + public float y = 0; + public float pressure = 0; + } + static { + touchEvents = new touchEvent[touchEventMax]; + for( int i = 0; i < touchEventMax; i++ ) + touchEvents[i] = new touchEvent(); + } // Startup public SDLSurface(Context context) { @@ -456,6 +473,76 @@ // Touch events public boolean onTouch(View v, MotionEvent event) { + if (multiTouch) + { + int action = -1; + if( event.getAction() == MotionEvent.ACTION_UP ) + { + action = 1; + for( int i = 0; i < touchEventMax; i++ ) + { + if( touchEvents[i].down ) + { + touchEvents[i].down = false; + SDLActivity.onNativeMultiTouch(action, touchEvents[i].x, touchEvents[i].y, i, touchEvents[i].pressure); + } + } + } + if( event.getAction() == MotionEvent.ACTION_DOWN ) + { + action = 0; + for( int i = 0; i < event.getPointerCount(); i++ ) + { + int id = event.getPointerId(i); + if( id >= touchEventMax ) + id = touchEventMax-1; + touchEvents[id].down = true; + touchEvents[id].x = event.getX(i); + touchEvents[id].y = event.getY(i); + touchEvents[id].pressure = event.getPressure(i); + SDLActivity.onNativeMultiTouch(action, touchEvents[id].x, touchEvents[id].y, id, touchEvents[id].pressure); + } + } + + if( event.getAction() == MotionEvent.ACTION_MOVE ) + { + for( int i = 0; i < touchEventMax; i++ ) + { + int ii; + for( ii = 0; ii < event.getPointerCount(); ii++ ) + { + if( i == event.getPointerId(ii) ) + break; + } + if( ii >= event.getPointerCount() ) + { + // Up event + if( touchEvents[i].down ) + { + action = 1; + touchEvents[i].down = false; + SDLActivity.onNativeMultiTouch(action, touchEvents[i].x, touchEvents[i].y, i, touchEvents[i].pressure); + } + } + else + { + int id = event.getPointerId(ii); + if( id >= touchEventMax ) + id = touchEventMax-1; + if( touchEvents[id].down ) + action = 2; + else + action = 0; + touchEvents[id].down = true; + touchEvents[id].x = event.getX(i); + touchEvents[id].y = event.getY(i); + touchEvents[id].pressure = event.getPressure(i); + SDLActivity.onNativeMultiTouch(action, touchEvents[id].x, touchEvents[id].y, id, touchEvents[id].pressure); + } + } + } + return true; + } int action = event.getAction(); float x = event.getX(); float y = event.getY(); diff -r f8588afb6486 src/core/android/SDL_android.cpp --- a/src/core/android/SDL_android.cpp Mon Feb 28 23:50:32 2011 -0800 +++ b/src/core/android/SDL_android.cpp Thu Mar 03 12:25:33 2011 +0100 @@ -44,8 +44,7 @@ /******************************************************************************* Globals *******************************************************************************/ -static JNIEnv* mEnv = NULL; -static JNIEnv* mAudioEnv = NULL; +static JavaVM* mJVM = NULL; // Main activity static jclass mActivityClass; @@ -57,6 +56,7 @@ static jmethodID midAudioWriteShortBuffer; static jmethodID midAudioWriteByteBuffer; static jmethodID midAudioQuit; +static jmethodID midSetActivityTitle; // Accelerometer data storage static float fLastAccelerometer[3]; @@ -76,25 +76,27 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls) { __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); + env->GetJavaVM(&mJVM); - mEnv = env; mActivityClass = cls; - midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass, + midCreateGLContext = env->GetStaticMethodID(mActivityClass, "createGLContext","(II)Z"); - midFlipBuffers = mEnv->GetStaticMethodID(mActivityClass, + midFlipBuffers = env->GetStaticMethodID(mActivityClass, "flipBuffers","()V"); - midAudioInit = mEnv->GetStaticMethodID(mActivityClass, + midAudioInit = env->GetStaticMethodID(mActivityClass, "audioInit", "(IZZI)Ljava/lang/Object;"); - midAudioWriteShortBuffer = mEnv->GetStaticMethodID(mActivityClass, + midAudioWriteShortBuffer = env->GetStaticMethodID(mActivityClass, "audioWriteShortBuffer", "([S)V"); - midAudioWriteByteBuffer = mEnv->GetStaticMethodID(mActivityClass, + midAudioWriteByteBuffer = env->GetStaticMethodID(mActivityClass, "audioWriteByteBuffer", "([B)V"); - midAudioQuit = mEnv->GetStaticMethodID(mActivityClass, + midAudioQuit = env->GetStaticMethodID(mActivityClass, "audioQuit", "()V"); + midSetActivityTitle = env->GetStaticMethodID(mActivityClass,"setActivityTitle","(Ljava/lang/String;)V"); + if(!midCreateGLContext || !midFlipBuffers || !midAudioInit || - !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) { + !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit ||!midSetActivityTitle) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); } } @@ -129,6 +131,14 @@ Android_OnTouch(action, x, y, p); } +// Multitouch +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeMultiTouch( + JNIEnv *, jclass, + jint action, jfloat x, jfloat y, jint pointerId, jfloat p) +{ + Android_OnMultiTouch(action, x, y, pointerId, p); +} + // Accelerometer extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel( JNIEnv* env, jclass jcls, @@ -151,37 +161,58 @@ JNIEnv* env, jclass cls) { /* This is the audio thread, with a different environment */ - mAudioEnv = env; - Android_RunAudioThread(); } +JNIEnv *getJNIEnv(SDL_bool &attached) +{ + JNIEnv *env = NULL; + int status; + attached = SDL_FALSE; + status = mJVM->GetEnv((void **) &env, JNI_VERSION_1_4); + if(status < 0) { + status = mJVM->AttachCurrentThread(&env, NULL); + if(status < 0) { + __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: failed to attach current thread!"); + return NULL; + } + attached = SDL_TRUE; + } + return env; +} /******************************************************************************* Functions called by SDL into Java *******************************************************************************/ extern "C" SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion) { - if (mEnv->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + if (env && env->CallStaticBooleanMethod(mActivityClass, midCreateGLContext, majorVersion, minorVersion)) { + if(isAttached) mJVM->DetachCurrentThread(); return SDL_TRUE; } else { + if(isAttached) mJVM->DetachCurrentThread(); return SDL_FALSE; } } extern "C" void Android_JNI_SwapWindow() { - mEnv->CallStaticVoidMethod(mActivityClass, midFlipBuffers); + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + if (env) + env->CallStaticVoidMethod(mActivityClass, midFlipBuffers); + if(isAttached) mJVM->DetachCurrentThread(); } extern "C" void Android_JNI_SetActivityTitle(const char *title) { - jmethodID mid; - - mid = mEnv->GetStaticMethodID(mActivityClass,"setActivityTitle","(Ljava/lang/String;)V"); - if (mid) { - mEnv->CallStaticVoidMethod(mActivityClass, mid, mEnv->NewStringUTF(title)); - } + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + if (env) + env->CallStaticVoidMethod(mActivityClass, midSetActivityTitle, env->NewStringUTF(title)); + if(isAttached) mJVM->DetachCurrentThread(); } extern "C" void Android_JNI_GetAccelerometerValues(float values[3]) @@ -202,32 +233,38 @@ extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) { + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + int audioBufferFrames; - + if (!env) + return 0; __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); audioBuffer16Bit = is16Bit; audioBufferStereo = channelCount > 1; - audioBuffer = mEnv->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames); + audioBuffer = env->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames); if (audioBuffer == NULL) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!"); + if(isAttached) mJVM->DetachCurrentThread(); return 0; } - audioBuffer = mEnv->NewGlobalRef(audioBuffer); + audioBuffer = env->NewGlobalRef(audioBuffer); jboolean isCopy = JNI_FALSE; if (audioBuffer16Bit) { - audioBufferPinned = mEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); - audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer); + audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); + audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer); } else { - audioBufferPinned = mEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy); - audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer); + audioBufferPinned = env->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy); + audioBufferFrames = env->GetArrayLength((jbyteArray)audioBuffer); } if (audioBufferStereo) { audioBufferFrames /= 2; } + if(isAttached) mJVM->DetachCurrentThread(); return audioBufferFrames; } @@ -238,26 +275,37 @@ extern "C" void Android_JNI_WriteAudioBuffer() { + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + if (env) + { if (audioBuffer16Bit) { - mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT); - mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer); + env->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT); + env->CallStaticVoidMethod(mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer); } else { - mAudioEnv->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT); - mAudioEnv->CallStaticVoidMethod(mActivityClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer); + env->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT); + env->CallStaticVoidMethod(mActivityClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer); } + } + if(isAttached) mJVM->DetachCurrentThread(); /* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */ } extern "C" void Android_JNI_CloseAudioDevice() { - mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit); + SDL_bool isAttached = SDL_FALSE; + JNIEnv *env = getJNIEnv(isAttached); + if (!env) + return; + env->CallStaticVoidMethod(mActivityClass, midAudioQuit); if (audioBuffer) { - mEnv->DeleteGlobalRef(audioBuffer); + env->DeleteGlobalRef(audioBuffer); audioBuffer = NULL; audioBufferPinned = NULL; } + if(isAttached) mJVM->DetachCurrentThread(); } /* vi: set ts=4 sw=4 expandtab: */ diff -r f8588afb6486 src/video/android/SDL_androidtouch.c --- a/src/video/android/SDL_androidtouch.c Mon Feb 28 23:50:32 2011 -0800 +++ b/src/video/android/SDL_androidtouch.c Thu Mar 03 12:25:33 2011 +0100 @@ -24,6 +24,7 @@ #include #include "SDL_events.h" +#include "../../events/SDL_touch_c.h" #include "../../events/SDL_mouse_c.h" #include "SDL_androidtouch.h" @@ -57,4 +58,23 @@ } } +void Android_OnMultiTouch(int action, float x, float y, int pointerId, float p) +{ + if (!Android_Window) { + return; + } + + SDL_Event event; + if(action == ACTION_MOVE) + { + SDL_SendTouchMotion(0, pointerId, SDL_FALSE, x, y, p); + } + else + { + SDL_bool down = (action == ACTION_DOWN ? SDL_TRUE : SDL_FALSE); + SDL_SendFingerDown(0, pointerId, down, x, y, p); + } +} + + /* vi: set ts=4 sw=4 expandtab: */ diff -r f8588afb6486 src/video/android/SDL_androidtouch.h --- a/src/video/android/SDL_androidtouch.h Mon Feb 28 23:50:32 2011 -0800 +++ b/src/video/android/SDL_androidtouch.h Thu Mar 03 12:25:33 2011 +0100 @@ -25,4 +25,6 @@ extern void Android_OnTouch(int action, float x, float y, float p); +extern void Android_OnMultiTouch(int action, float x, float y, int pointerId, float p); + /* vi: set ts=4 sw=4 expandtab: */ diff -r f8588afb6486 src/video/android/SDL_androidwindow.c --- a/src/video/android/SDL_androidwindow.c Mon Feb 28 23:50:32 2011 -0800 +++ b/src/video/android/SDL_androidwindow.c Thu Mar 03 12:25:33 2011 +0100 @@ -22,6 +22,7 @@ #include "SDL_config.h" #include "../SDL_sysvideo.h" +#include "../../events/SDL_touch_c.h" #include "SDL_androidvideo.h" #include "SDL_androidwindow.h" @@ -46,6 +47,21 @@ window->flags |= SDL_WINDOW_SHOWN; /* only one window on Android */ window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */ + SDL_Touch touch; + memset( &touch, 0, sizeof(touch) ); + touch.x_min = touch.y_min = touch.pressure_min = 0.0f; + touch.pressure_max = 1000000; + touch.x_max = Android_ScreenWidth; + touch.y_max = Android_ScreenHeight; + + touch.native_xres = touch.native_yres = (float)(1<<(16-1)); + + touch.pressureres = 1; + touch.native_pressureres = 1.0f; + touch.id = 0; + + SDL_AddTouch(&touch, "Android touch screen"); + SDL_SetTouchFocus(0, window); return 0; } @@ -59,6 +75,7 @@ Android_DestroyWindow(_THIS, SDL_Window * window) { if (window == Android_Window) { + SDL_DelTouch(0); Android_Window = NULL; } }