diff -r 19f5760dc1a7 README-android.txt --- a/README-android.txt dom nov 03 11:34:03 2013 -0800 +++ b/README-android.txt mar nov 05 14:49:30 2013 -0300 @@ -4,13 +4,14 @@ Requirements: -Android SDK (version 10 or later) +Android SDK (version 12 or later) http://developer.android.com/sdk/index.html Android NDK r7 or later http://developer.android.com/sdk/ndk/index.html Minimum API level supported by SDL: 10 (Android 2.3.3) +Joystick support is available for API level >=12 devices. ================================================================================ How the port works @@ -396,8 +397,11 @@ Why is API level 10 the minimum required? ================================================================================ -API level 10 is required because SDL requires some functionality for running not -available on older devices and some for building which is not in older NDK/SDKs. +API level 10 is the minimum required level at runtime (that is, on the device) +because SDL requires some functionality for running not +available on older devices. Since the incorporation of joystick support into SDL, +the minimum SDK required to *build* SDL is version 12. Devices running API levels +10-11 are still supported, only with the joystick functionality disabled. Support for native OpenGL ES and ES2 applications was introduced in the NDK for API level 4 and 8. EGL was made a stable API in the NDK for API level 9, which diff -r 19f5760dc1a7 WhatsNew.txt --- a/WhatsNew.txt dom nov 03 11:34:03 2013 -0800 +++ b/WhatsNew.txt mar nov 05 14:49:30 2013 -0300 @@ -2,6 +2,16 @@ This is a list of major changes in SDL's version history. --------------------------------------------------------------------------- +2.0.2: +--------------------------------------------------------------------------- + +Android: +* Joystick support (minimum SDK version required to build SDL is now 12, + the required runtime version remains at 10, but on such devices joystick + support won't be available). + + +--------------------------------------------------------------------------- 2.0.1: --------------------------------------------------------------------------- diff -r 19f5760dc1a7 android-project/AndroidManifest.xml --- a/android-project/AndroidManifest.xml dom nov 03 11:34:03 2013 -0800 +++ b/android-project/AndroidManifest.xml mar nov 05 14:49:30 2013 -0300 @@ -31,7 +31,7 @@ - + diff -r 19f5760dc1a7 android-project/default.properties --- a/android-project/default.properties dom nov 03 11:34:03 2013 -0800 +++ b/android-project/default.properties mar nov 05 14:49:30 2013 -0300 @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-7 +target=android-12 diff -r 19f5760dc1a7 android-project/jni/Application.mk --- a/android-project/jni/Application.mk dom nov 03 11:34:03 2013 -0800 +++ b/android-project/jni/Application.mk mar nov 05 14:49:30 2013 -0300 @@ -2,3 +2,5 @@ # Uncomment this if you're using STL in your project # See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information # APP_STL := stlport_static + +APP_ABI := armeabi armeabi-v7a x86 diff -r 19f5760dc1a7 android-project/project.properties --- a/android-project/project.properties dom nov 03 11:34:03 2013 -0800 +++ b/android-project/project.properties mar nov 05 14:49:30 2013 -0300 @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-10 +target=android-12 diff -r 19f5760dc1a7 android-project/src/org/libsdl/app/SDLActivity.java --- a/android-project/src/org/libsdl/app/SDLActivity.java dom nov 03 11:34:03 2013 -0800 +++ b/android-project/src/org/libsdl/app/SDLActivity.java mar nov 05 14:49:30 2013 -0300 @@ -16,6 +16,10 @@ import android.media.*; import android.hardware.*; +import java.lang.*; +import java.util.List; +import java.util.ArrayList; + /** SDL Activity @@ -31,10 +35,11 @@ protected static SDLSurface mSurface; protected static View mTextEdit; protected static ViewGroup mLayout; + protected static SDLJoystickHandler mJoystickHandler; // This is what SDL runs in. It invokes SDL_main(), eventually protected static Thread mSDLThread; - + // Audio protected static Thread mAudioThread; protected static AudioTrack mAudioTrack; @@ -60,6 +65,13 @@ // Set up the surface mSurface = new SDLSurface(getApplication()); + + if(Build.VERSION.SDK_INT >= 12) { + mJoystickHandler = new SDLJoystickHandler_API12(); + } + else { + mJoystickHandler = new SDLJoystickHandler(); + } mLayout = new AbsoluteLayout(this); mLayout.addView(mSurface); @@ -236,6 +248,10 @@ public static native void nativePause(); public static native void nativeResume(); public static native void onNativeResize(int x, int y, int format); + public static native void onNativePadDown(int padId, int keycode); + public static native void onNativePadUp(int padId, int keycode); + public static native void onNativeJoy(int joyId, int axis, + float value); public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeKeyboardFocusLost(); @@ -406,6 +422,23 @@ } return Arrays.copyOf(filtered, used); } + + // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance + public static int getNumJoysticks() { + return mJoystickHandler.getNumJoysticks(); + } + + public static String getJoystickName(int joy) { + return mJoystickHandler.getJoystickName(joy); + } + + public static int getJoystickAxes(int joy) { + return mJoystickHandler.getJoystickAxes(joy); + } + + public static int getJoyId(int devId) { + return mJoystickHandler.getJoyId(devId); + } } /** @@ -451,6 +484,10 @@ mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + + if(Build.VERSION.SDK_INT >= 12) { + setOnGenericMotionListener(new SDLGenericMotionHandler_API12()); + } // Some arbitrary defaults to avoid a potential division by zero mWidth = 1.0f; @@ -557,16 +594,26 @@ // Key events @Override public boolean onKey(View v, int keyCode, KeyEvent event) { - - if (event.getAction() == KeyEvent.ACTION_DOWN) { - //Log.v("SDL", "key down: " + keyCode); - SDLActivity.onNativeKeyDown(keyCode); - return true; - } - else if (event.getAction() == KeyEvent.ACTION_UP) { - //Log.v("SDL", "key up: " + keyCode); - SDLActivity.onNativeKeyUp(keyCode); - return true; + // Dispatch the different events depending on where they come from + if(event.getSource() == InputDevice.SOURCE_KEYBOARD) { + if (event.getAction() == KeyEvent.ACTION_DOWN) { + //Log.v("SDL", "key down: " + keyCode); + SDLActivity.onNativeKeyDown(keyCode); + return true; + } + else if (event.getAction() == KeyEvent.ACTION_UP) { + //Log.v("SDL", "key up: " + keyCode); + SDLActivity.onNativeKeyUp(keyCode); + return true; + } + } else if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */ + (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { + int id = SDLActivity.getJoyId( event.getDeviceId() ); + if (event.getAction() == KeyEvent.ACTION_DOWN) { + SDLActivity.onNativePadDown(id, keyCode); + } else if (event.getAction() == KeyEvent.ACTION_UP) { + SDLActivity.onNativePadUp(id, keyCode); + } } return false; @@ -646,8 +693,7 @@ y / SensorManager.GRAVITY_EARTH, event.values[2] / SensorManager.GRAVITY_EARTH - 1); } - } - + } } /* This is a fake invisible editor view that receives the input and defines the @@ -769,3 +815,95 @@ } +/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */ +class SDLJoystickHandler { + public int getNumJoysticks() { + return 0; + } + + public String getJoystickName(int joy) { + return ""; + } + + public int getJoystickAxes(int joy) { + return 0; + } + + public int getJoyId(int devId) { + return 0; + } +} + +/* Actual joystick functionality available for API >= 12 devices */ +class SDLJoystickHandler_API12 extends SDLJoystickHandler { + private List mJoyIdList; + + // Create a list of valid ID's the first time this function is called + private void createJoystickList() { + if(mJoyIdList != null) { + return; + } + + mJoyIdList = new ArrayList(); + int[] deviceIds = InputDevice.getDeviceIds(); + for(int i=0; iGetStaticMethodID(env, mActivityClass, "getNumJoysticks", "()I"); + if (!mid) { + return -1; + } + + return (int)(*env)->CallStaticIntMethod(env, mActivityClass, mid); +} + +/* Return the name of joystick number "i" */ +char* Android_JNI_GetJoystickName(int i) +{ + JNIEnv* env = Android_JNI_GetEnv(); + if (!env) { + return SDL_strdup(""); + } + + jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "getJoystickName", "(I)Ljava/lang/String;"); + if (!mid) { + return SDL_strdup(""); + } + jstring string = (jstring)((*env)->CallStaticObjectMethod(env, mActivityClass, mid, i)); + const char* utf = (*env)->GetStringUTFChars(env, string, 0); + if (!utf) { + return SDL_strdup(""); + } + + char* text = SDL_strdup(utf); + (*env)->ReleaseStringUTFChars(env, string, utf); + return text; +} + +/* return the number of axes in the given joystick */ +int Android_JNI_GetJoystickAxes(int joy) +{ + JNIEnv* env = Android_JNI_GetEnv(); + if (!env) { + return -1; + } + + jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "getJoystickAxes", "(I)I"); + if (!mid) { + return -1; + } + + return (int)(*env)->CallIntMethod(env, mActivityClass, mid, joy); +} + + /* sends message to be handled on the UI event dispatch thread */ int Android_JNI_SendMessage(int command, int param) { diff -r 19f5760dc1a7 src/core/android/SDL_android.h --- a/src/core/android/SDL_android.h dom nov 03 11:34:03 2013 -0800 +++ b/src/core/android/SDL_android.h mar nov 05 14:49:30 2013 -0300 @@ -64,6 +64,11 @@ /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); + +/* Joystick support */ +int Android_JNI_GetNumJoysticks(); +char* Android_JNI_GetJoystickName(int i); +int Android_JNI_GetJoystickAxes(int joy); /* Touch support */ int Android_JNI_GetTouchDeviceIds(int **ids); diff -r 19f5760dc1a7 src/joystick/android/SDL_sysjoystick.c --- a/src/joystick/android/SDL_sysjoystick.c dom nov 03 11:34:03 2013 -0800 +++ b/src/joystick/android/SDL_sysjoystick.c mar nov 05 14:49:30 2013 -0300 @@ -29,11 +29,48 @@ #include "SDL_error.h" #include "SDL_events.h" #include "SDL_joystick.h" +#include "SDL_hints.h" #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" #include "../../core/android/SDL_android.h" -static const char *accelerometerName = "Android accelerometer"; +#define ANDROID_ACCELEROMETER_INDEX (SYS_numjoysticks - 1) +#define ANDROID_ACCELEROMETER_NAME "Android Accelerometer" + +static SDL_Joystick **SYS_Joysticks; +static char **SYS_JoystickNames; +static int SYS_numjoysticks; +static SDL_bool SYS_accelAsJoy; + +/* Function to convert Android keyCodes into SDL ones. + * This code manipulation is done to get a sequential list of codes. + */ +int +keycode_to_SDL(int keycode) +{ + int final = 0; + /* D-Pad key codes (API 1): + * KEYCODE_DPAD_UP=19, KEYCODE_DPAD_DOWN + * KEYCODE_DPAD_LEFT, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_CENTER + */ + if(keycode < 96) + return keycode-19; + /* Some gamepad buttons (API 9): + * KEYCODE_BUTTON_A=96, KEYCODE_BUTTON_B, KEYCODE_BUTTON_C, + * KEYCODE_BUTTON_X, KEYCODE_BUTTON_Y, KEYCODE_BUTTON_Z, + * KEYCODE_BUTTON_L1, KEYCODE_BUTTON_L2, + * KEYCODE_BUTTON_R1, KEYCODE_BUTTON_R2, + * KEYCODE_BUTTON_THUMBL, KEYCODE_BUTTON_THUMBR, + * KEYCODE_BUTTON_START, KEYCODE_BUTTON_SELECT, KEYCODE_BUTTON_MODE + */ + else if(keycode < 188) + return keycode-91; + /* More gamepad buttons (API 12): + * KEYCODE_BUTTON_1=188 to KEYCODE_BUTTON_16 + */ + else + return keycode-168; +} /* Function to scan the system for joysticks. * This function should set SDL_numjoysticks to the number of available @@ -43,18 +80,57 @@ int SDL_SYS_JoystickInit(void) { - return (1); + int i = 0; + const char *env; + + // Should we emulate the accelerometer as a joystick? + env = SDL_GetHint(SDL_HINT_ACCEL_AS_JOY); + if (env && !SDL_atoi(env)) + SYS_accelAsJoy = SDL_FALSE; + else + SYS_accelAsJoy = SDL_TRUE; /* Default behavior */ + + SYS_numjoysticks = Android_JNI_GetNumJoysticks(); + if (SYS_accelAsJoy) { + SYS_numjoysticks++; + } + SYS_Joysticks = (SDL_Joystick **)SDL_malloc(SYS_numjoysticks*sizeof(SDL_Joystick *)); + if (SYS_Joysticks == NULL) + { + return SDL_OutOfMemory(); + } + SYS_JoystickNames = (char **)SDL_malloc(SYS_numjoysticks*sizeof(char *)); + if (SYS_JoystickNames == NULL) + { + SDL_free(SYS_Joysticks); + SYS_Joysticks = NULL; + return SDL_OutOfMemory(); + } + SDL_memset(SYS_JoystickNames, 0, (SYS_numjoysticks*sizeof(char *))); + SDL_memset(SYS_Joysticks, 0, (SYS_numjoysticks*sizeof(SDL_Joystick *))); + + for (i = 0; i < SYS_numjoysticks; i++) + { + if ( SYS_accelAsJoy && i == ANDROID_ACCELEROMETER_INDEX ) { + SYS_JoystickNames[i] = ANDROID_ACCELEROMETER_NAME; + } else { + SYS_JoystickNames[i] = Android_JNI_GetJoystickName(i); + } + } + + return (SYS_numjoysticks); } int SDL_SYS_NumJoysticks() { - return 1; + return SYS_numjoysticks; } void SDL_SYS_JoystickDetect() { } +/* TODO: Hotplugging support */ SDL_bool SDL_SYS_JoystickNeedsPolling() { return SDL_FALSE; @@ -64,7 +140,7 @@ const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index) { - return accelerometerName; + return SYS_JoystickNames[device_index]; } /* Function to perform the mapping from device index to the instance id for this index */ @@ -81,11 +157,19 @@ int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) { - if (device_index == 0) { - joystick->nbuttons = 0; + if (device_index < SYS_numjoysticks) { joystick->nhats = 0; joystick->nballs = 0; - joystick->naxes = 3; + if (SYS_accelAsJoy && device_index == ANDROID_ACCELEROMETER_INDEX) { + joystick->nbuttons = 0; + joystick->naxes = 3; + } else { + // TODO: Get the real number of buttons in the device + joystick->nbuttons = 36; + joystick->naxes = Android_JNI_GetJoystickAxes(device_index); + } + + SYS_Joysticks[device_index] = joystick; return 0; } else { SDL_SetError("No joystick available with that index"); @@ -111,7 +195,8 @@ Sint16 value; float values[3]; - if (Android_JNI_GetAccelerometerValues(values)) { + if (SYS_accelAsJoy && Android_JNI_GetAccelerometerValues(values) && + joystick->instance_id == ANDROID_ACCELEROMETER_INDEX) { for ( i = 0; i < 3; i++ ) { value = (Sint16)(values[i] * 32767.0f); SDL_PrivateJoystickAxis(joystick, i, value); @@ -129,6 +214,10 @@ void SDL_SYS_JoystickQuit(void) { + SDL_free(SYS_JoystickNames); + SDL_free(SYS_Joysticks); + SYS_JoystickNames = NULL; + SYS_Joysticks = NULL; } SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) @@ -151,6 +240,32 @@ return guid; } +int +Android_OnPadDown(int padId, int keycode) +{ + SDL_PrivateJoystickButton(SYS_Joysticks[padId], keycode_to_SDL(keycode), SDL_PRESSED); + + return 0; +} + +int +Android_OnPadUp(int padId, int keycode) +{ + SDL_PrivateJoystickButton(SYS_Joysticks[padId], keycode_to_SDL(keycode), SDL_RELEASED); + + return 0; +} + +int +Android_OnJoy(int joyId, int axis, float value) +{ + // Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] + // TODO: Are the reported values right? + SDL_PrivateJoystickAxis(SYS_Joysticks[joyId], axis, (Sint16) (32767.*value) ); + + return 0; +} + #endif /* SDL_JOYSTICK_ANDROID */ /* vi: set ts=4 sw=4 expandtab: */ diff -r 19f5760dc1a7 src/joystick/android/SDL_sysjoystick.h --- /dev/null jue ene 01 00:00:00 1970 +0000 +++ b/src/joystick/android/SDL_sysjoystick.h mar nov 05 14:49:30 2013 -0300 @@ -0,0 +1,28 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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. + + 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: + + 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. + */ + +#include "SDL_config.h" + +extern int Android_OnPadDown(int padId, int keycode); +extern int Android_OnPadUp(int padId, int keycode); +extern int Android_OnJoy(int joyId, int axisnum, float value); + +/* vi: set ts=4 sw=4 expandtab: */