--- 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
Binary file android-project/res/drawable-hdpi/icon.png has changed
Binary file android-project/res/drawable-ldpi/icon.png has changed
Binary file android-project/res/drawable-mdpi/icon.png has changed
--- /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] );
+ }
+ }
+
+
+}
+
+