# HG changeset patch # User Xeli # Date 1327369671 -3600 # Node ID cf12f07d6f24139f339bdedb220400a104c59541 # Parent 2abf9ea19a38334fb15ba26d8f0e78e381296865 update the core/android/SDL_android.cpp fix some includes in Android.mks, use a different host to download some libs, sdl doesn't have up to date tarballs.. diff -r 2abf9ea19a38 -r cf12f07d6f24 project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp --- a/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp Tue Jan 24 01:59:28 2012 +0100 +++ b/project_files/Android-build/SDL-android-project/jni/SDL/src/core/android/SDL_android.cpp Tue Jan 24 02:47:51 2012 +0100 @@ -1,30 +1,28 @@ /* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2011 Sam Lantinga + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. */ - -#define org_hedgewars_hedgeroid org_hedgewars_hedgeroid - #include "SDL_config.h" #include "SDL_stdinc.h" +#ifdef __ANDROID__ + #include "SDL_android.h" extern "C" { @@ -33,7 +31,15 @@ #include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidvideo.h" -/* Impelemented in audio/android/SDL_androidaudio.c */ +#include +#define LOG_TAG "SDL_android" +//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#define LOGI(...) do {} while (false) +#define LOGE(...) do {} while (false) + + +/* Implemented in audio/android/SDL_androidaudio.c */ extern void Android_RunAudioThread(); } // C @@ -49,6 +55,7 @@ *******************************************************************************/ static JNIEnv* mEnv = NULL; static JNIEnv* mAudioEnv = NULL; +static JavaVM* mJavaVM; // Main activity static jclass mActivityClass; @@ -63,7 +70,7 @@ // Accelerometer data storage static float fLastAccelerometer[3]; - +static bool bHasNewData; /******************************************************************************* Functions called by JNI @@ -72,6 +79,14 @@ // Library init extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { + JNIEnv *env; + mJavaVM = vm; + LOGI("JNI_OnLoad called"); + if (mJavaVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("Failed to get the environment using GetEnv()"); + return -1; + } + return JNI_VERSION_1_4; } @@ -81,7 +96,7 @@ __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); mEnv = env; - mActivityClass = cls; + mActivityClass = (jclass)env->NewGlobalRef(cls); midCreateGLContext = mEnv->GetStaticMethodID(mActivityClass, "createGLContext","(II)Z"); @@ -96,10 +111,13 @@ midAudioQuit = mEnv->GetStaticMethodID(mActivityClass, "audioQuit", "()V"); + bHasNewData = false; + if(!midCreateGLContext || !midFlipBuffers || !midAudioInit || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); } + __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!"); } // Resize @@ -140,7 +158,8 @@ { fLastAccelerometer[0] = x; fLastAccelerometer[1] = y; - fLastAccelerometer[2] = z; + fLastAccelerometer[2] = z; + bHasNewData = true; } // Quit @@ -151,7 +170,27 @@ SDL_SendQuit(); } -extern "C" void Java_org_hedgewars_hedgeroid_SDLActivity_nativeRunAudioThread( +// Pause +extern "C" void Java_org_libsdl_app_SDLActivity_nativePause( + JNIEnv* env, jclass cls) +{ + if (Android_Window) { + SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); + SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); + } +} + +// Resume +extern "C" void Java_org_libsdl_app_SDLActivity_nativeResume( + JNIEnv* env, jclass cls) +{ + if (Android_Window) { + SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); + SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0); + } +} + +extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread( JNIEnv* env, jclass cls) { /* This is the audio thread, with a different environment */ @@ -188,12 +227,20 @@ } } -extern "C" void Android_JNI_GetAccelerometerValues(float values[3]) +extern "C" SDL_bool Android_JNI_GetAccelerometerValues(float values[3]) { int i; - for (i = 0; i < 3; ++i) { - values[i] = fLastAccelerometer[i]; + SDL_bool retval = SDL_FALSE; + + if (bHasNewData) { + for (i = 0; i < 3; ++i) { + values[i] = fLastAccelerometer[i]; + } + bHasNewData = false; + retval = SDL_TRUE; } + + return retval; } // @@ -208,29 +255,48 @@ { int audioBufferFrames; + int status; + JNIEnv *env; + static bool isAttached = false; + status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4); + if(status < 0) { + LOGE("callback_handler: failed to get JNI environment, assuming native thread"); + status = mJavaVM->AttachCurrentThread(&env, NULL); + if(status < 0) { + LOGE("callback_handler: failed to attach current thread"); + return 0; + } + isAttached = true; + } + + __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!"); 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) { + mJavaVM->DetachCurrentThread(); + } return audioBufferFrames; } @@ -255,13 +321,323 @@ extern "C" void Android_JNI_CloseAudioDevice() { - mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit); + int status; + JNIEnv *env; + static bool isAttached = false; + status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4); + if(status < 0) { + LOGE("callback_handler: failed to get JNI environment, assuming native thread"); + status = mJavaVM->AttachCurrentThread(&env, NULL); + if(status < 0) { + LOGE("callback_handler: failed to attach current thread"); + return; + } + isAttached = true; + } + + env->CallStaticVoidMethod(mActivityClass, midAudioQuit); if (audioBuffer) { - mEnv->DeleteGlobalRef(audioBuffer); + env->DeleteGlobalRef(audioBuffer); audioBuffer = NULL; audioBufferPinned = NULL; } + + if (isAttached) { + mJavaVM->DetachCurrentThread(); + } +} + +// Test for an exception and call SDL_SetError with its detail if one occurs +static bool Android_JNI_ExceptionOccurred() +{ + jthrowable exception = mEnv->ExceptionOccurred(); + if (exception != NULL) { + jmethodID mid; + + // Until this happens most JNI operations have undefined behaviour + mEnv->ExceptionClear(); + + jclass exceptionClass = mEnv->GetObjectClass(exception); + jclass classClass = mEnv->FindClass("java/lang/Class"); + + mid = mEnv->GetMethodID(classClass, "getName", "()Ljava/lang/String;"); + jstring exceptionName = (jstring)mEnv->CallObjectMethod(exceptionClass, mid); + const char* exceptionNameUTF8 = mEnv->GetStringUTFChars(exceptionName, 0); + + mid = mEnv->GetMethodID(exceptionClass, "getMessage", "()Ljava/lang/String;"); + jstring exceptionMessage = (jstring)mEnv->CallObjectMethod(exception, mid); + + if (exceptionMessage != NULL) { + const char* exceptionMessageUTF8 = mEnv->GetStringUTFChars( + exceptionMessage, 0); + SDL_SetError("%s: %s", exceptionNameUTF8, exceptionMessageUTF8); + mEnv->ReleaseStringUTFChars(exceptionMessage, exceptionMessageUTF8); + mEnv->DeleteLocalRef(exceptionMessage); + } else { + SDL_SetError("%s", exceptionNameUTF8); + } + + mEnv->ReleaseStringUTFChars(exceptionName, exceptionNameUTF8); + mEnv->DeleteLocalRef(exceptionName); + mEnv->DeleteLocalRef(classClass); + mEnv->DeleteLocalRef(exceptionClass); + mEnv->DeleteLocalRef(exception); + + return true; + } + + return false; +} + +static int Android_JNI_FileOpen(SDL_RWops* ctx) +{ + int result = 0; + + jmethodID mid; + jobject context; + jobject assetManager; + jobject inputStream; + jclass channels; + jobject readableByteChannel; + jstring fileNameJString; + + bool allocatedLocalFrame = false; + + if (mEnv->PushLocalFrame(16) < 0) { + SDL_SetError("Failed to allocate enough JVM local references"); + goto failure; + } else { + allocatedLocalFrame = true; + } + + fileNameJString = (jstring)ctx->hidden.androidio.fileName; + + // context = SDLActivity.getContext(); + mid = mEnv->GetStaticMethodID(mActivityClass, + "getContext","()Landroid/content/Context;"); + context = mEnv->CallStaticObjectMethod(mActivityClass, mid); + + // assetManager = context.getAssets(); + mid = mEnv->GetMethodID(mEnv->GetObjectClass(context), + "getAssets", "()Landroid/content/res/AssetManager;"); + assetManager = mEnv->CallObjectMethod(context, mid); + + // inputStream = assetManager.open(); + mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager), + "open", "(Ljava/lang/String;)Ljava/io/InputStream;"); + inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString); + if (Android_JNI_ExceptionOccurred()) { + goto failure; + } + + ctx->hidden.androidio.inputStream = inputStream; + ctx->hidden.androidio.inputStreamRef = mEnv->NewGlobalRef(inputStream); + + // Despite all the visible documentation on [Asset]InputStream claiming + // that the .available() method is not guaranteed to return the entire file + // size, comments in /samples//ApiDemos/src/com/example/ ... + // android/apis/content/ReadAsset.java imply that Android's + // AssetInputStream.available() /will/ always return the total file size + + // size = inputStream.available(); + mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), + "available", "()I"); + ctx->hidden.androidio.size = mEnv->CallIntMethod(inputStream, mid); + if (Android_JNI_ExceptionOccurred()) { + goto failure; + } + + // readableByteChannel = Channels.newChannel(inputStream); + channels = mEnv->FindClass("java/nio/channels/Channels"); + mid = mEnv->GetStaticMethodID(channels, + "newChannel", + "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;"); + readableByteChannel = mEnv->CallStaticObjectMethod( + channels, mid, inputStream); + if (Android_JNI_ExceptionOccurred()) { + goto failure; + } + + ctx->hidden.androidio.readableByteChannel = readableByteChannel; + ctx->hidden.androidio.readableByteChannelRef = + mEnv->NewGlobalRef(readableByteChannel); + + // Store .read id for reading purposes + mid = mEnv->GetMethodID(mEnv->GetObjectClass(readableByteChannel), + "read", "(Ljava/nio/ByteBuffer;)I"); + ctx->hidden.androidio.readMethod = mid; + + ctx->hidden.androidio.position = 0; + + if (false) { +failure: + result = -1; + + mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef); + + if(ctx->hidden.androidio.inputStreamRef != NULL) { + mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.inputStreamRef); + } + } + + if (allocatedLocalFrame) { + mEnv->PopLocalFrame(NULL); + } + + return result; } +extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx, + const char* fileName, const char*) +{ + if (!ctx) { + return -1; + } + + jstring fileNameJString = mEnv->NewStringUTF(fileName); + ctx->hidden.androidio.fileName = fileNameJString; + ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString); + ctx->hidden.androidio.inputStreamRef = NULL; + mEnv->DeleteLocalRef(fileNameJString); + + return Android_JNI_FileOpen(ctx); +} + +extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, + size_t size, size_t maxnum) +{ + int bytesRemaining = size * maxnum; + int bytesRead = 0; + + jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannel; + jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; + jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining); + + while (bytesRemaining > 0) { + // result = readableByteChannel.read(...); + int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer); + + if (Android_JNI_ExceptionOccurred()) { + mEnv->DeleteLocalRef(byteBuffer); + return 0; + } + + if (result < 0) { + break; + } + + bytesRemaining -= result; + bytesRead += result; + ctx->hidden.androidio.position += result; + } + + mEnv->DeleteLocalRef(byteBuffer); + + return bytesRead / size; +} + +extern "C" size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, + size_t size, size_t num) +{ + SDL_SetError("Cannot write to Android package filesystem"); + return 0; +} + +static int Android_JNI_FileClose(SDL_RWops* ctx, bool release) +{ + int result = 0; + + if (ctx) { + if (release) { + mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef); + } + + jobject inputStream = (jobject)ctx->hidden.androidio.inputStream; + + // inputStream.close(); + jmethodID mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), + "close", "()V"); + mEnv->CallVoidMethod(inputStream, mid); + mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.inputStreamRef); + mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.readableByteChannelRef); + if (Android_JNI_ExceptionOccurred()) { + result = -1; + } + + if (release) { + SDL_FreeRW(ctx); + } + } + + return result; +} + + +extern "C" long Android_JNI_FileSeek(SDL_RWops* ctx, long offset, int whence) +{ + long newPosition; + + switch (whence) { + case RW_SEEK_SET: + newPosition = offset; + break; + case RW_SEEK_CUR: + newPosition = ctx->hidden.androidio.position + offset; + break; + case RW_SEEK_END: + newPosition = ctx->hidden.androidio.size + offset; + break; + default: + SDL_SetError("Unknown value for 'whence'"); + return -1; + } + if (newPosition < 0) { + newPosition = 0; + } + if (newPosition > ctx->hidden.androidio.size) { + newPosition = ctx->hidden.androidio.size; + } + + long movement = newPosition - ctx->hidden.androidio.position; + jobject inputStream = (jobject)ctx->hidden.androidio.inputStream; + + if (movement > 0) { + unsigned char buffer[1024]; + + // The easy case where we're seeking forwards + while (movement > 0) { + long amount = (long) sizeof (buffer); + if (amount > movement) { + amount = movement; + } + size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount); + + if (result <= 0) { + // Failed to read/skip the required amount, so fail + return -1; + } + + movement -= result; + } + } else if (movement < 0) { + // We can't seek backwards so we have to reopen the file and seek + // forwards which obviously isn't very efficient + Android_JNI_FileClose(ctx, false); + Android_JNI_FileOpen(ctx); + Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET); + } + + ctx->hidden.androidio.position = newPosition; + + return ctx->hidden.androidio.position; +} + +extern "C" int Android_JNI_FileClose(SDL_RWops* ctx) +{ + return Android_JNI_FileClose(ctx, true); +} + +#endif /* __ANDROID__ */ + /* vi: set ts=4 sw=4 expandtab: */ diff -r 2abf9ea19a38 -r cf12f07d6f24 project_files/Android-build/SDL-android-project/jni/SDL_mixer/Android.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/jni/SDL_mixer/Android.mk Tue Jan 24 02:47:51 2012 +0100 @@ -0,0 +1,20 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := SDL_mixer + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../../../../misc/libtremor \ + $(LOCAL_PATH)/.. \ + $(LOCAL_PATH)/../SDL/include \ + $(LOCAL_PATH)/../mikmod/include \ + +LOCAL_CFLAGS := -DWAV_MUSIC -DOGG_MUSIC -DOGG_USE_TREMOR -DMOD_MUSIC + +LOCAL_SRC_FILES := $(notdir $(filter-out %/playmus.c %/playwave.c, $(wildcard $(LOCAL_PATH)/*.c))) + +LOCAL_SHARED_LIBRARIES := SDL mikmod +LOCAL_STATIC_LIBRARIES := tremor + +include $(BUILD_SHARED_LIBRARY) diff -r 2abf9ea19a38 -r cf12f07d6f24 project_files/Android-build/SDL-android-project/jni/SDL_ttf/Android.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/jni/SDL_ttf/Android.mk Tue Jan 24 02:47:51 2012 +0100 @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := SDL_ttf + +LOCAL_CFLAGS := -I$(LOCAL_PATH)/../SDL/include -I$(LOCAL_PATH)/../../../../../misc/libfreetype/include + +LOCAL_SRC_FILES := SDL_ttf.c + +LOCAL_SHARED_LIBRARIES := SDL + +LOCAL_STATIC_LIBRARIES := freetype + +LOCAL_LDLIBS := -lz + +include $(BUILD_SHARED_LIBRARY) diff -r 2abf9ea19a38 -r cf12f07d6f24 project_files/Android-build/download_libs.sh --- a/project_files/Android-build/download_libs.sh Tue Jan 24 01:59:28 2012 +0100 +++ b/project_files/Android-build/download_libs.sh Tue Jan 24 02:47:51 2012 +0100 @@ -7,12 +7,12 @@ mv SDL-android-project/jni/tmp/* SDL-android-project/jni/$2 #move the tmp dir to the jni directory rm tmp.zip #remove old tmp dir } -download_and_zip http://www.libsdl.org/projects/SDL_image/libs/jpegsr8d.zip jpeg -download_and_zip http://www.libsdl.org/projects/SDL_image/libs/lpng157.zip png +download_and_zip http://www.xelification.com/tmp/jpeg.zip jpeg +download_and_zip http://www.xelification.com/tmp/png.zip png download_and_zip http://www.libsdl.org/projects/SDL_image/release/SDL_image-1.2.12.zip SDL_image download_and_zip http://www.libsdl.org/projects/SDL_mixer/release/SDL_mixer-1.2.12.zip SDL_mixer download_and_zip http://www.xelification.com/tmp/mikmod.zip mikmod #temporary url since the libsdl.org site doesn't work at the moment -download_and_zip http://www.libsdl.org/projects/SDL_net/release/SDL_net-1.2.8.zip SDL_net +download_and_zip http://www.xelification.com/tmp/SDL_net.zip SDL_net download_and_zip http://www.libsdl.org/projects/SDL_ttf/release/SDL_ttf-2.0.11.zip SDL_ttf download_and_zip http://www.libsdl.org/tmp/SDL-1.3.zip SDL