Mercurial > sdl-ios-xcode
changeset 4965:91d0085b7560
Added the Android project and lots of info to README.android
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 06 Jan 2011 17:12:31 -0800 |
parents | 6c645018741e |
children | a130bc2f0a18 |
files | README.android android-project/AndroidManifest.xml android-project/build.properties android-project/build.xml android-project/default.properties android-project/jni/Android.mk android-project/jni/src/Android.mk android-project/local.properties android-project/res/drawable-hdpi/icon.png android-project/res/drawable-ldpi/icon.png android-project/res/drawable-mdpi/icon.png android-project/res/layout/main.xml android-project/res/values/strings.xml android-project/src/org/libsdl/app/SDLActivity.java |
diffstat | 14 files changed, 608 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/README.android Thu Jan 06 16:11:21 2011 -0800 +++ b/README.android Thu Jan 06 17:12:31 2011 -0800 @@ -2,8 +2,13 @@ Simple DirectMedia Layer for Android ================================================================================ -Requirements: Android SDK and Android NDK r4 or later -http://developer.android.com/ +Requirements: + +Android SDK +http://developer.android.com/sdk/index.html + +Android NDK r4 or later +http://developer.android.com/sdk/ndk/index.html ================================================================================ How the port works @@ -22,7 +27,7 @@ ================================================================================ Instructions: -1. Copy the android-project directory wherever you want your Android project to go +1. Copy the android-project directory wherever you want to keep your projects and rename it to the name of your project. 2. Move this SDL directory into the <project>/jni directory 3. Place your application source files in the <project>/jni/src directory 4. Edit <project>/jni/src/Android.mk to include your source files @@ -35,16 +40,54 @@ creates a .apk with the native code embedded 8. 'ant install' will push the apk to the device or emulator (if connected) +Here's an explanation of the files in the Android project, so you can customize them: + +android-project/ + AndroidManifest.xml - package manifest, do not modify + build.properties - empty + build.xml - build description file, used by ant + default.properties - holds the ABI for the application, currently android-4 which corresponds to the Android 1.6 system image + local.properties - holds the SDK path, you should change this to the path to your SDK + jni/ - directory holding native code and Android.mk + jni/Android.mk - Android makefile that includes all subdirectories + jni/SDL/ - directory holding the SDL library files + jni/SDL/Android.mk - Android makefile for creating the SDL shared library + jni/src/ - directory holding your application source + jni/src/Android.mk - Android makefile that you should customize to include your source code and any library references + res/ - directory holding resources for your application + res/drawable-* - directories holding icons for different phone hardware + res/layout/main.xml - place holder for the main screen layout, overridden by the SDL video output + res/values/strings.xml - strings used in your application, including the application name shown on the phone. + src/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding to SDL. Be very careful changing this, as the SDL library relies on this implementation. + + +================================================================================ + Additional documentation +================================================================================ + +The documentation in the NDK docs directory is very helpful in understanding the build process and how to work with native code on the Android platform. + +The best place to start is with docs/OVERVIEW.TXT + ================================================================================ Using Eclipse ================================================================================ -NEED CONTENT +First make sure that you've installed Eclipse and the Android extensions as described here: + http://developer.android.com/sdk/eclipse-adt.html + +Once you've copied the SDL android project and customized it, you can create an Eclipse project from it: + * File -> New -> Other + * Select the Android -> Android Project wizard and click Next + * Enter the name you'd like your project to have + * Select "Create project from existing source" and browse for your project directory + * Make sure the Build Target is set to Android 1.6 + * Click Finish ================================================================================ - Loading files + Loading files and resources ================================================================================ NEED CONTENT @@ -54,7 +97,20 @@ Troubleshooting ================================================================================ -NEED CONTENT +You can create and run an emulator from the Eclipse IDE: + * Window -> Android SDK and AVD Manager + +You can see if adb can see any devices with the following command: + adb devices + +You can see the output of log messages on the default device with: + adb logcat + +You can push files to the device with: + adb push local_file remote_path_and_file + +You can push files to the SD Card at /sdcard, for example: + adb push moose.dat /sdcard/moose.dat ================================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/AndroidManifest.xml Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.libsdl.app" + android:versionCode="1" + android:versionName="1.0"> + <application android:label="@string/app_name" android:icon="@drawable/icon"> + <activity android:name="SDLActivity" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/build.properties Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/build.xml Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="SDLApp" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked in in Version + Control Systems. --> + <property file="local.properties" /> + + <!-- The build.properties file can be created by you and is never touched + by the 'android' tool. This is the place to change some of the default property values + used by the Ant rules. + Here are some properties you may want to change/update: + + application.package + the name of your application package as defined in the manifest. Used by the + 'uninstall' rule. + source.dir + the name of the source directory. Default is 'src'. + out.dir + the name of the output directory. Default is 'bin'. + + Properties related to the SDK location or the project target should be updated + using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. + + --> + <property file="build.properties" /> + + <!-- The default.properties file is created and updated by the 'android' tool, as well + as ADT. + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. --> + <property file="default.properties" /> + + <!-- Custom Android task to deal with the project target, and import the proper rules. + This requires ant 1.6.0 or above. --> + <path id="android.antlibs"> + <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" /> + <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" /> + <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" /> + <pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" /> + <pathelement path="${sdk.dir}/tools/lib/jarutils.jar" /> + </path> + + <taskdef name="setup" + classname="com.android.ant.SetupTask" + classpathref="android.antlibs" /> + + <!-- Execute the Android Setup task that will setup some properties specific to the target, + and import the build rules files. + + The rules file is imported from + <SDK>/platforms/<target_platform>/templates/android_rules.xml + + To customize some build steps for your project: + - copy the content of the main node <project> from android_rules.xml + - paste it in this build.xml below the <setup /> task. + - disable the import by changing the setup task below to <setup import="false" /> + + This will ensure that the properties are setup correctly but that your customized + build steps are used. + --> + <setup /> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/default.properties Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/jni/Android.mk Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,1 @@ +include $(call all-subdir-makefiles)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/jni/src/Android.mk Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := main + +SDL_PATH := ../SDL + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include + +# Add your application source files here... +LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.cpp \ + YourSourceHere.c + +LOCAL_SHARED_LIBRARIES := SDL + +LOCAL_LDLIBS := -lGLESv1_CM -llog + +include $(BUILD_SHARED_LIBRARY)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/local.properties Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked in Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir=/Users/hercules/eclipse/android-sdk-mac_86
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/res/layout/main.xml Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > +<TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Hello World, SDLActivity" + /> +</LinearLayout> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/res/values/strings.xml Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">SDL App</string> +</resources>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android-project/src/org/libsdl/app/SDLActivity.java Thu Jan 06 17:12:31 2011 -0800 @@ -0,0 +1,389 @@ +package org.libsdl.app; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.egl.*; + +import android.app.*; +import android.content.*; +import android.view.*; +import android.os.*; +import android.util.Log; +import android.graphics.*; +import android.text.method.*; +import android.text.*; +import android.media.*; +import android.hardware.*; +import android.content.*; + +import java.lang.*; + + +/** + SDL Activity +*/ +public class SDLActivity extends Activity { + + //Main components + private static SDLActivity mSingleton; + private static SDLSurface mSurface; + + //Audio + private static AudioTrack mAudioTrack; + private static boolean bAudioIsEnabled; + + //Sensors + private static boolean bAccelIsEnabled; + + //feature IDs. Must match up on the C side as well. + private static int FEATURE_AUDIO = 1; + private static int FEATURE_ACCEL = 2; + + //Load the .so + static { + System.loadLibrary("SDL"); + System.loadLibrary("main"); + } + + //Setup + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + //So we can call stuff from static callbacks + mSingleton = this; + + //Set up the surface + mSurface = new SDLSurface(getApplication()); + setContentView(mSurface); + SurfaceHolder holder = mSurface.getHolder(); + holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); + + } + + //Audio + public static boolean initAudio(){ + + //blah. Hardcoded things are bad. FIXME when we have more sound stuff + //working properly. + mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, + 11025, + AudioFormat.CHANNEL_CONFIGURATION_MONO, + AudioFormat.ENCODING_PCM_8BIT, + 2048, + AudioTrack.MODE_STREAM); + bAudioIsEnabled = true; + return true; + } + + //Accel + public static boolean initAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); + bAccelIsEnabled = true; + return true; + } + + public static boolean closeAccel(){ + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false); + bAccelIsEnabled = false; + return true; + } + + + //Events + protected void onPause() { + super.onPause(); + } + + protected void onResume() { + super.onResume(); + } + + + + + + //C functions we call + public static native void nativeInit(); + public static native void nativeQuit(); + public static native void nativeSetScreenSize(int width, int height); + public static native void onNativeKeyDown(int keycode); + public static native void onNativeKeyUp(int keycode); + public static native void onNativeTouch(int action, float x, + float y, float p); + public static native void onNativeResize(int x, int y, int format); + public static native void onNativeAccel(float x, float y, float z); + + + + //Java functions called from C + private static void createGLContext(){ + mSurface.initEGL(); + } + + public static void flipBuffers(){ + mSurface.flipEGL(); + } + + public static void updateAudio(byte [] buf){ + + if(mAudioTrack == null){ + return; + } + + mAudioTrack.write(buf, 0, buf.length); + mAudioTrack.play(); + + Log.v("SDL","Played some audio"); + } + + public static void enableFeature(int featureid, int enabled){ + Log.v("SDL","Feature " + featureid + " = " + enabled); + + //Yuck. This is all horribly inelegent. If it gets to more than a few + //'features' I'll rip this out and make something nicer, I promise :) + if(featureid == FEATURE_AUDIO){ + if(enabled == 1){ + initAudio(); + }else{ + //We don't have one of these yet... + //closeAudio(); + } + } + + else if(featureid == FEATURE_ACCEL){ + if(enabled == 1){ + initAccel(); + }else{ + closeAccel(); + } + } + } + + + + + + + +} + +/** + Simple nativeInit() runnable +*/ +class SDLRunner implements Runnable{ + public void run(){ + //SDLActivity.initAudio(); + + //Runs SDL_main() + SDLActivity.nativeInit(); + + Log.v("SDL","SDL thread terminated"); + } +} + + +/** + SDLSurface. This is what we draw on, so we need to know when it's created + in order to do anything useful. + + Because of this, that's where we set up the SDL thread +*/ +class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, + View.OnKeyListener, View.OnTouchListener, SensorEventListener { + + //This is what SDL runs in. It invokes SDL_main(), eventually + private Thread mSDLThread; + + //EGL private objects + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private EGLDisplay mEGLDisplay; + + //Sensors + private static SensorManager mSensorManager; + + //Startup + public SDLSurface(Context context) { + super(context); + getHolder().addCallback(this); + + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + setOnKeyListener(this); + setOnTouchListener(this); + + mSensorManager = (SensorManager)context.getSystemService("sensor"); + } + + //Called when we have a valid drawing surface + public void surfaceCreated(SurfaceHolder holder) { + Log.v("SDL","Surface created"); + + int width = getWidth(); + int height = getHeight(); + + //Set the width and height variables in C before we start SDL so we have + //it available on init + SDLActivity.nativeSetScreenSize(width, height); + + //Now start up the C app thread + mSDLThread = new Thread(new SDLRunner(), "SDLThread"); + mSDLThread.start(); + } + + //Called when we lose the surface + public void surfaceDestroyed(SurfaceHolder holder) { + Log.v("SDL","Surface destroyed"); + + SDLActivity.nativeQuit(); + + //Now wait for the SDL thread to quit + try{ + mSDLThread.wait(); + }catch(Exception e){ + Log.v("SDL","Problem stopping thread: " + e); + } + } + + //Called when the surface is resized + public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + Log.v("SDL","Surface resized"); + + SDLActivity.onNativeResize(width, height, format); + } + + //unused + public void onDraw(Canvas canvas) {} + + + //EGL functions + public boolean initEGL(){ + Log.v("SDL","Starting up"); + + try{ + + EGL10 egl = (EGL10)EGLContext.getEGL(); + + EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + int[] version = new int[2]; + egl.eglInitialize(dpy, version); + + int[] configSpec = { + //EGL10.EGL_DEPTH_SIZE, 16, + EGL10.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] num_config = new int[1]; + egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config); + EGLConfig config = configs[0]; + + EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null); + + EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null); + + egl.eglMakeCurrent(dpy, surface, surface, ctx); + + mEGLContext = ctx; + mEGLDisplay = dpy; + mEGLSurface = surface; + + + }catch(Exception e){ + Log.v("SDL", e + ""); + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } + } + Log.v("SDL","Done making!"); + + return true; + } + + //EGL buffer flip + public void flipEGL(){ + try{ + + EGL10 egl = (EGL10)EGLContext.getEGL(); + GL10 gl = (GL10)mEGLContext.getGL(); + + egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null); + + //drawing here + + egl.eglWaitGL(); + + egl.eglSwapBuffers(mEGLDisplay, mEGLSurface); + + + }catch(Exception e){ + Log.v("SDL", "flipEGL(): " + e); + + for(StackTraceElement s : e.getStackTrace()){ + Log.v("SDL", s.toString()); + } + } + } + + + + //Key events + public boolean onKey(View v, int keyCode, KeyEvent event){ + + if(event.getAction() == KeyEvent.ACTION_DOWN){ + SDLActivity.onNativeKeyDown(keyCode); + return true; + } + + else if(event.getAction() == KeyEvent.ACTION_UP){ + SDLActivity.onNativeKeyUp(keyCode); + return true; + } + + return false; + } + + //Touch events + public boolean onTouch(View v, MotionEvent event){ + + int action = event.getAction(); + float x = event.getX(); + float y = event.getY(); + float p = event.getPressure(); + + //TODO: Anything else we need to pass? + SDLActivity.onNativeTouch(action, x, y, p); + return true; + } + + //Sensor events + public void enableSensor(int sensortype, boolean enabled){ + //TODO: This uses getDefaultSensor - what if we have >1 accels? + if(enabled){ + mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(sensortype), + SensorManager.SENSOR_DELAY_GAME, null); + }else{ + mSensorManager.unregisterListener(this, + mSensorManager.getDefaultSensor(sensortype)); + } + } + + public void onAccuracyChanged(Sensor sensor, int accuracy){ + //TODO + } + + public void onSensorChanged(SensorEvent event){ + if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ + SDLActivity.onNativeAccel( event.values[0], + event.values[1], + event.values[2] ); + } + } + + +} + +