project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
branchhedgeroid
changeset 7857 2bc61f8841a1
parent 7584 7831c84cc644
child 9080 9b42757d7e71
equal deleted inserted replaced
7855:ddcdedd3330b 7857:2bc61f8841a1
       
     1 /*
       
     2  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
       
     4  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
       
     5  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
       
     6  *
       
     7  * This program is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2
       
    10  * of the License, or (at your option) any later version.
       
    11  *
       
    12  * This program is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    15  * GNU General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License
       
    18  * along with this program; if not, write to the Free Software
       
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    20  */
       
    21 
     1 package org.hedgewars.hedgeroid;
    22 package org.hedgewars.hedgeroid;
       
    23 
       
    24 import java.io.IOException;
       
    25 import java.io.UnsupportedEncodingException;
       
    26 import java.net.ConnectException;
     2 
    27 
     3 import javax.microedition.khronos.egl.EGL10;
    28 import javax.microedition.khronos.egl.EGL10;
     4 import javax.microedition.khronos.egl.EGLConfig;
    29 import javax.microedition.khronos.egl.EGLConfig;
     5 import javax.microedition.khronos.egl.EGLContext;
    30 import javax.microedition.khronos.egl.EGLContext;
     6 import javax.microedition.khronos.egl.EGLDisplay;
    31 import javax.microedition.khronos.egl.EGLDisplay;
     7 import javax.microedition.khronos.egl.EGLSurface;
    32 import javax.microedition.khronos.egl.EGLSurface;
     8 
    33 
     9 import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
    34 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
    10 import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
       
    11 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    35 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
       
    36 import org.hedgewars.hedgeroid.netplay.Netplay;
       
    37 import org.hedgewars.hedgeroid.util.FileUtils;
    12 
    38 
    13 import android.app.Activity;
    39 import android.app.Activity;
    14 import android.content.Context;
    40 import android.content.Context;
    15 import android.graphics.Canvas;
    41 import android.graphics.Canvas;
    16 import android.graphics.PixelFormat;
    42 import android.graphics.PixelFormat;
    20 import android.hardware.SensorManager;
    46 import android.hardware.SensorManager;
    21 import android.media.AudioFormat;
    47 import android.media.AudioFormat;
    22 import android.media.AudioManager;
    48 import android.media.AudioManager;
    23 import android.media.AudioTrack;
    49 import android.media.AudioTrack;
    24 import android.os.Bundle;
    50 import android.os.Bundle;
    25 import android.os.Handler;
    51 import android.util.Base64;
    26 import android.os.Message;
       
    27 import android.util.DisplayMetrics;
    52 import android.util.DisplayMetrics;
    28 import android.util.Log;
    53 import android.util.Log;
    29 import android.view.KeyEvent;
    54 import android.view.KeyEvent;
    30 import android.view.MotionEvent;
    55 import android.view.MotionEvent;
    31 import android.view.SurfaceHolder;
    56 import android.view.SurfaceHolder;
    35 
    60 
    36 /**
    61 /**
    37     SDL Activity
    62     SDL Activity
    38  */
    63  */
    39 public class SDLActivity extends Activity {
    64 public class SDLActivity extends Activity {
    40 
    65 	/**
       
    66 	 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all
       
    67 	 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended
       
    68 	 * way to do this (http://developer.android.com/guide/faq/framework.html#3)
       
    69 	 */
       
    70 	public static volatile GameConfig startConfig;
       
    71 	public static volatile boolean startNetgame;
       
    72 	
    41 	// Main components
    73 	// Main components
    42 	public static SDLActivity mSingleton;
    74 	public static SDLActivity mSingleton;
    43 	private static SDLSurface mSurface;
    75 	private static SDLSurface mSurface;
    44 
       
    45 	// This is what SDL runs in. It invokes SDL_main(), eventually
       
    46 	private static Thread mSDLThread;
    76 	private static Thread mSDLThread;
    47 
    77 
    48 	// Audio
    78 	// Audio
    49 	private static Thread mAudioThread;
    79 	private static Thread mAudioThread;
    50 	private static AudioTrack mAudioTrack;
    80 	private static AudioTrack mAudioTrack;
    57 	private static int mGLMajor, mGLMinor;
    87 	private static int mGLMajor, mGLMinor;
    58 
    88 
    59 	// Load the .so
    89 	// Load the .so
    60 	static {
    90 	static {
    61 		System.loadLibrary("SDL");
    91 		System.loadLibrary("SDL");
    62 		//System.loadLibrary("SDL_image");
       
    63 		//System.loadLibrary("SDL_mixer");
       
    64 		//System.loadLibrary("SDL_ttf");
       
    65 		System.loadLibrary("main");
    92 		System.loadLibrary("main");
    66 	}
    93 	}
    67 
    94 
    68 	// Setup
    95 	// Setup
    69 	protected void onCreate(Bundle savedInstanceState) {
    96 	protected void onCreate(Bundle savedInstanceState) {
    70 		//Log.v("SDL", "onCreate()");
       
    71 		super.onCreate(savedInstanceState);
    97 		super.onCreate(savedInstanceState);
    72 
    98 
    73 		// So we can call stuff from static callbacks
    99 		// So we can call stuff from static callbacks
    74 		mSingleton = this;
   100 		mSingleton = this;
    75 
   101 
    76 		// Set up the surface
   102 		// Set up the surface
    77 		GameConfig config = getIntent().getParcelableExtra("config");
   103 		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
    78 
   104 		startConfig = null;
    79 		mSurface = new SDLSurface(getApplication(), config);
       
    80 		setContentView(mSurface);
   105 		setContentView(mSurface);
    81 		SurfaceHolder holder = mSurface.getHolder();
       
    82 	}
   106 	}
    83 
   107 
    84 	// Events
   108 	// Events
    85 	protected void onPause() {
   109 	protected void onPause() {
    86 		Log.v("SDL", "onPause()");
   110 		Log.v("SDL", "onPause()");
   104 	protected void onDestroy() {
   128 	protected void onDestroy() {
   105 		super.onDestroy();
   129 		super.onDestroy();
   106 		Log.v("SDL", "onDestroy()");
   130 		Log.v("SDL", "onDestroy()");
   107 		// Send a quit message to the application
   131 		// Send a quit message to the application
   108 		SDLActivity.nativeQuit();
   132 		SDLActivity.nativeQuit();
   109 
       
   110 		// Now wait for the SDL thread to quit
   133 		// Now wait for the SDL thread to quit
   111 		if (mSDLThread != null) {
   134 		if (mSDLThread != null) {
   112 			try {
   135 			try {
   113 				mSDLThread.join();
   136 				mSDLThread.join();
   114 			} catch(Exception e) {
   137 			} catch(Exception e) {
   115 				Log.v("SDL", "Problem stopping thread: " + e);
   138 				Log.w("SDL", "Problem stopping thread: " + e);
   116 			}
   139 			}
   117 			mSDLThread = null;
   140 			mSDLThread = null;
   118 
   141 		}
   119 			//Log.v("SDL", "Finished waiting for SDL thread");
   142 		mSingleton = null;
   120 		}
   143 	}
   121 	}
   144 	
   122 
   145 	public static void synchronizedNativeInit(String...args) {
   123 	// Messages from the SDLMain thread
   146 		synchronized(PascalExports.engineMutex) {
   124 	static int COMMAND_CHANGE_TITLE = 1;
   147 			nativeInit(args);
   125 
   148 		}
   126 	// Handler for the messages
   149 	}
   127 	Handler commandHandler = new Handler() {
   150 	
   128 		public void handleMessage(Message msg) {
       
   129 			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
       
   130 				setTitle((String)msg.obj);
       
   131 			}
       
   132 		}
       
   133 	};
       
   134 
       
   135 	// Send a message from the SDLMain thread
       
   136 	void sendCommand(int command, Object data) {
       
   137 		Message msg = commandHandler.obtainMessage();
       
   138 		msg.arg1 = command;
       
   139 		msg.obj = data;
       
   140 		commandHandler.sendMessage(msg);
       
   141 	}
       
   142 
       
   143 	// C functions we call
   151 	// C functions we call
   144 	public static native void nativeInit(String...args);
   152 	private static native void nativeInit(String...args);
   145 	public static native void nativeQuit();
   153 	public static native void nativeQuit();
   146 	public static native void nativePause();
   154 	public static native void nativePause();
   147 	public static native void nativeResume();
   155 	public static native void nativeResume();
   148 	public static native void onNativeResize(int x, int y, int format);
   156 	public static native void onNativeResize(int x, int y, int format);
   149 	public static native void onNativeKeyDown(int keycode);
   157 	public static native void onNativeKeyDown(int keycode);
   163 
   171 
   164 	public static void flipBuffers() {
   172 	public static void flipBuffers() {
   165 		flipEGL();
   173 		flipEGL();
   166 	}
   174 	}
   167 
   175 
   168 	public static void setActivityTitle(String title) {
   176 	public static void setActivityTitle(final String title) {
   169 		// Called from SDLMain() thread and can't directly affect the view
   177 		// Called from SDLMain() thread and can't directly affect the view
   170 		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
   178 		mSingleton.runOnUiThread(new Runnable() {
       
   179 			public void run() {
       
   180 				mSingleton.setTitle(title);
       
   181 			}
       
   182 		});
   171 	}
   183 	}
   172 
   184 
   173 	public static Context getContext() {
   185 	public static Context getContext() {
   174 		return mSingleton;
   186 		return mSingleton;
   175 	}
   187 	}
   176 
   188 
   177 	public static void startApp(int width, int height, GameConfig config) {
   189 	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
   178 		// Start up the C app thread
   190 		// Start up the C app thread
   179 		if (mSDLThread == null) {
   191 		if (mSDLThread == null) {
   180 			mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread");
   192 			mSDLThread = new Thread(new SDLMain(width, height, config, netgame));
   181 			mSDLThread.start();
   193 			mSDLThread.start();
   182 		}
   194 		} else {
   183 		else {
       
   184 			SDLActivity.nativeResume();
   195 			SDLActivity.nativeResume();
   185 		}
   196 		}
   186 	}
   197 	}
   187 
   198 
   188 	// EGL functions
   199 	// EGL functions
   189 	public static boolean initEGL(int majorVersion, int minorVersion) {
   200 	public static boolean initEGL(int majorVersion, int minorVersion) {
   190 		if (SDLActivity.mEGLDisplay == null) {
   201 		if (SDLActivity.mEGLDisplay == null) {
   191 			//Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
       
   192 
       
   193 			try {
   202 			try {
   194 				EGL10 egl = (EGL10)EGLContext.getEGL();
   203 				EGL10 egl = (EGL10)EGLContext.getEGL();
   195 
   204 
   196 				EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
   205 				EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
   197 
   206 
   205 					renderableType = EGL_OPENGL_ES2_BIT;
   214 					renderableType = EGL_OPENGL_ES2_BIT;
   206 				} else if (majorVersion == 1) {
   215 				} else if (majorVersion == 1) {
   207 					renderableType = EGL_OPENGL_ES_BIT;
   216 					renderableType = EGL_OPENGL_ES_BIT;
   208 				}
   217 				}
   209 				int[] configSpec = {
   218 				int[] configSpec = {
   210 						//EGL10.EGL_DEPTH_SIZE,   16,
       
   211 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
   219 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
   212 						EGL10.EGL_NONE
   220 						EGL10.EGL_NONE
   213 				};
   221 				};
   214 				EGLConfig[] configs = new EGLConfig[1];
   222 				EGLConfig[] configs = new EGLConfig[1];
   215 				int[] num_config = new int[1];
   223 				int[] num_config = new int[1];
   217 					Log.e("SDL", "No EGL config available");
   225 					Log.e("SDL", "No EGL config available");
   218 					return false;
   226 					return false;
   219 				}
   227 				}
   220 				EGLConfig config = configs[0];
   228 				EGLConfig config = configs[0];
   221 
   229 
   222 				/*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
       
   223                 int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
       
   224                 EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
       
   225 
       
   226                 if (ctx == EGL10.EGL_NO_CONTEXT) {
       
   227                     Log.e("SDL", "Couldn't create context");
       
   228                     return false;
       
   229                 }
       
   230                 SDLActivity.mEGLContext = ctx;*/
       
   231 				SDLActivity.mEGLDisplay = dpy;
   230 				SDLActivity.mEGLDisplay = dpy;
   232 				SDLActivity.mEGLConfig = config;
   231 				SDLActivity.mEGLConfig = config;
   233 				SDLActivity.mGLMajor = majorVersion;
   232 				SDLActivity.mGLMajor = majorVersion;
   234 				SDLActivity.mGLMinor = minorVersion;
   233 				SDLActivity.mGLMinor = minorVersion;
   235 
   234 
   411 
   410 
   412 /**
   411 /**
   413     Simple nativeInit() runnable
   412     Simple nativeInit() runnable
   414  */
   413  */
   415 class SDLMain implements Runnable {
   414 class SDLMain implements Runnable {
   416 
   415 	public static final String TAG = "SDLMain";
   417 	private int surfaceWidth, surfaceHeight;
   416 	
   418 	private GameConfig config;
   417     public static final int RQ_LOWRES            = 0x00000001; // use half land array
   419 
   418     public static final int RQ_BLURRY_LAND       = 0x00000002; // downscaled terrain
   420 	public SDLMain(int width, int height, GameConfig _config) {
   419     public static final int RQ_NO_BACKGROUND     = 0x00000004; // don't draw background
   421 		config = _config;
   420     public static final int RQ_SIMPLE_ROPE       = 0x00000008; // avoid drawing rope
       
   421     public static final int RQ_2D_WATER          = 0x00000010; // disabe 3D water effect
       
   422     public static final int RQ_SIMPLE_EXPLOSIONS = 0x00000020; // no fancy explosion effects
       
   423     public static final int RQ_NO_FLAKES         = 0x00000040; // no flakes
       
   424     public static final int RQ_NO_MENU_ANIM      = 0x00000080; // ammomenu appears with no animation
       
   425     public static final int RQ_NO_DROPLETS       = 0x00000100; // no droplets
       
   426     public static final int RQ_NO_CLAMPING       = 0x00000200; // don't clamp textures
       
   427     public static final int RQ_NO_TOOLTIPS       = 0x00000400; // tooltips are not drawn
       
   428     public static final int RQ_NO_VSYNC          = 0x00000800; // don't sync on vblank
       
   429 	
       
   430 	private final int surfaceWidth, surfaceHeight;
       
   431 	private final String playerName;
       
   432 	private final GameConfig config;
       
   433 	private final boolean netgame;
       
   434 	
       
   435 	public SDLMain(int width, int height, GameConfig config, boolean netgame) {
   422 		surfaceWidth = width;
   436 		surfaceWidth = width;
   423 		surfaceHeight = height;
   437 		surfaceHeight = height;
       
   438 		if(netgame) {
       
   439 			playerName = Netplay.getAppInstance(SDLActivity.getContext().getApplicationContext()).getPlayerName();
       
   440 		} else {
       
   441 			playerName = "Player";
       
   442 		}
       
   443 		this.config = config;
       
   444 		this.netgame = netgame;
   424 	}
   445 	}
   425 
   446 
   426 	public void run() {
   447 	public void run() {
   427 		//Set up the IPC socket server to communicate with the engine
   448 		//Set up the IPC socket server to communicate with the engine
   428 		EngineProtocolNetwork ipc = new EngineProtocolNetwork(config);
   449 		GameConnection gameConn;
   429 
   450 		String path;
   430 		String path = Utils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
       
   431 		path = path.substring(0, path.length()-1);//remove the trailing '/'
       
   432 
       
   433 
       
   434 		// Runs SDL_main() with added parameters
       
   435 		SDLActivity.nativeInit(new String[] { String.valueOf(ipc.port),
       
   436 				String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
       
   437 				"0", "en.txt", "xeli", "1", "1", "1", path, ""  });
       
   438 
       
   439 		try {
   451 		try {
   440 			ipc.quitIPC();
   452 			if(netgame) {
   441 			ipc.join();
   453 				Netplay netplay = Netplay.getAppInstance(SDLActivity.mSingleton.getApplicationContext());
   442 		} catch (InterruptedException e) {
   454 				gameConn = GameConnection.forNetgame(config, netplay);
   443 			e.printStackTrace();
   455 			} else {
   444 		}
   456 				gameConn = GameConnection.forLocalGame(config);
   445 		Log.v("SDL", "SDL thread terminated");
   457 			}
   446 		//Log.v("SDL", "SDL thread terminated");
   458 			
       
   459 			path = FileUtils.getDataPathFile(SDLActivity.mSingleton).getAbsolutePath();
       
   460 			Log.d(TAG, "Starting engine");
       
   461 			// Runs SDL_main() with added parameters
       
   462 			try {
       
   463 				String pPort = String.valueOf(gameConn.port);
       
   464 				String pWidth = String.valueOf(surfaceWidth);
       
   465 				String pHeight = String.valueOf(surfaceHeight);
       
   466 				String pQuality = Integer.toString(RQ_NO_FLAKES|RQ_NO_DROPLETS|RQ_SIMPLE_EXPLOSIONS);
       
   467 				String pPlayerName = Base64.encodeToString(playerName.getBytes("UTF-8"), 0);
       
   468 				SDLActivity.synchronizedNativeInit(new String[] { pPort, pWidth, pHeight, pQuality, "en.txt", pPlayerName, "1", "1", "1", path, ""  });
       
   469 			} catch (UnsupportedEncodingException e) {
       
   470 				throw new AssertionError(e); // never happens
       
   471 			}
       
   472 			Log.d(TAG, "Engine stopped");
       
   473 		} catch(ConnectException e) {
       
   474 			Log.e(TAG, "Error starting IPC connection");
       
   475 		} catch (IOException e) {
       
   476 			Log.e(TAG, "Missing SDCard");
       
   477 		}
       
   478 		SDLActivity.mSingleton.runOnUiThread(new Runnable() { public void run() {
       
   479 			if(SDLActivity.mSingleton != null) {
       
   480 				SDLActivity.mSingleton.finish();
       
   481 			}
       
   482 		}});
   447 	}
   483 	}
   448 }
   484 }
   449 
   485 
   450 
   486 
   451 /**
   487 /**
   456  */
   492  */
   457 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
   493 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
   458 View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
   494 View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
   459 
   495 
   460 	private GameConfig config;
   496 	private GameConfig config;
   461 
   497 	private boolean netgame;
       
   498 	
   462 	// Sensors
   499 	// Sensors
   463 	private static SensorManager mSensorManager;
   500 	private static SensorManager mSensorManager;
   464 
   501 
   465 	// Startup    
   502 	// Startup    
   466 	public SDLSurface(Context context, GameConfig _config) {
   503 	public SDLSurface(Context context, GameConfig _config, boolean netgame) {
   467 		super(context);
   504 		super(context);
   468 		getHolder().addCallback(this); 
   505 		getHolder().addCallback(this); 
   469 
   506 
   470 		setFocusable(true);
   507 		setFocusable(true);
   471 		setFocusableInTouchMode(true);
   508 		setFocusableInTouchMode(true);
   473 		setOnKeyListener(this); 
   510 		setOnKeyListener(this); 
   474 		setOnTouchListener(this);   
   511 		setOnTouchListener(this);   
   475 
   512 
   476 		mSensorManager = (SensorManager)context.getSystemService("sensor");
   513 		mSensorManager = (SensorManager)context.getSystemService("sensor");
   477 		config = _config;
   514 		config = _config;
       
   515 		this.netgame = netgame;
   478 	}
   516 	}
   479 
   517 
   480 	// Called when we have a valid drawing surface
   518 	// Called when we have a valid drawing surface
   481 	public void surfaceCreated(SurfaceHolder holder) {
   519 	public void surfaceCreated(SurfaceHolder holder) {
   482 		Log.v("SDL", "surfaceCreated()");
   520 		Log.v("SDL", "surfaceCreated()");
   542 			break;
   580 			break;
   543 		}
   581 		}
   544 		SDLActivity.onNativeResize(width, height, sdlFormat);
   582 		SDLActivity.onNativeResize(width, height, sdlFormat);
   545 		Log.v("SDL", "Window size:" + width + "x"+height);
   583 		Log.v("SDL", "Window size:" + width + "x"+height);
   546 
   584 
   547 		SDLActivity.startApp(width, height, config);
   585 		SDLActivity.startApp(width, height, config, netgame);
   548 	}
   586 	}
   549 
   587 
   550 	// unused
   588 	// unused
   551 	public void onDraw(Canvas canvas) {}
   589 	public void onDraw(Canvas canvas) {}
   552 
   590 
   555 
   593 
   556 	// Key events
   594 	// Key events
   557 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
   595 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
   558 		switch(keyCode){
   596 		switch(keyCode){
   559 		case KeyEvent.KEYCODE_BACK:
   597 		case KeyEvent.KEYCODE_BACK:
   560 		        PascalExports.HWterminate(true);
   598 			Log.d("SDL", "KEYCODE_BACK");
   561                         return true;
   599 			SDLActivity.nativeQuit();
       
   600             return true;
   562 		case KeyEvent.KEYCODE_VOLUME_DOWN:
   601 		case KeyEvent.KEYCODE_VOLUME_DOWN:
   563 		case KeyEvent.KEYCODE_VOLUME_UP:
   602 		case KeyEvent.KEYCODE_VOLUME_UP:
   564 		case KeyEvent.KEYCODE_VOLUME_MUTE:
   603 		case KeyEvent.KEYCODE_VOLUME_MUTE:
   565 			return false;
   604 			return false;
   566 		}
   605 		}
   578 		return false;
   617 		return false;
   579 	}
   618 	}
   580 
   619 
   581 	// Touch events
   620 	// Touch events
   582 	public boolean onTouch(View v, MotionEvent event) {
   621 	public boolean onTouch(View v, MotionEvent event) {
   583 		{
   622 		final int action = event.getAction() & MotionEvent.ACTION_MASK;
   584 			final int touchDevId = event.getDeviceId();
   623 		final int actionPointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;		
   585 			final int pointerCount = event.getPointerCount();
   624 
   586 			// touchId, pointerId, action, x, y, pressure
   625 		if (action == MotionEvent.ACTION_MOVE) {
   587 			int actionPointerIndex = event.getActionIndex();
   626 			// TODO send motion to every pointer if its position has
   588 			int pointerFingerId = event.getPointerId(actionPointerIndex);
   627 			// changed since prev event.
   589 			int action = event.getActionMasked();
   628 			for (int i = 0; i < event.getPointerCount(); i++) {
   590 
   629 				sendNativeTouch(event, action, i);
   591 			float x = event.getX(actionPointerIndex);
   630 			}
   592 			float y = event.getY(actionPointerIndex);
   631 		} else {
   593 			float p = event.getPressure(actionPointerIndex);
   632 			sendNativeTouch(event, action, actionPointerIndex);
   594 
       
   595 			if (action == MotionEvent.ACTION_MOVE && pointerCount > 1) {
       
   596 				// TODO send motion to every pointer if its position has
       
   597 				// changed since prev event.
       
   598 				for (int i = 0; i < pointerCount; i++) {
       
   599 					pointerFingerId = event.getPointerId(i);
       
   600 					x = event.getX(i);
       
   601 					y = event.getY(i);
       
   602 					p = event.getPressure(i);
       
   603 					SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
       
   604 				}
       
   605 			} else {
       
   606 				SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
       
   607 			}
       
   608 		}
   633 		}
   609 		return true;
   634 		return true;
   610 	} 
   635 	} 
       
   636 	
       
   637 	private static void sendNativeTouch(MotionEvent event, int action, int pointerIndex) {
       
   638 		int touchDevId = event.getDeviceId();
       
   639 		int pointerFingerId = event.getPointerId(pointerIndex);
       
   640 		float x = event.getX(pointerIndex);
       
   641 		float y = event.getY(pointerIndex);
       
   642 		float pressure = event.getPressure(pointerIndex);
       
   643 		SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, pressure);
       
   644 	}
   611 
   645 
   612 	// Sensor events
   646 	// Sensor events
   613 	public void enableSensor(int sensortype, boolean enabled) {
   647 	public void enableSensor(int sensortype, boolean enabled) {
   614 		// TODO: This uses getDefaultSensor - what if we have >1 accels?
   648 		// TODO: This uses getDefaultSensor - what if we have >1 accels?
   615 		if (enabled) {
   649 		if (enabled) {
   631 			SDLActivity.onNativeAccel(event.values[0] / SensorManager.GRAVITY_EARTH,
   665 			SDLActivity.onNativeAccel(event.values[0] / SensorManager.GRAVITY_EARTH,
   632 					event.values[1] / SensorManager.GRAVITY_EARTH,
   666 					event.values[1] / SensorManager.GRAVITY_EARTH,
   633 					event.values[2] / SensorManager.GRAVITY_EARTH);
   667 					event.values[2] / SensorManager.GRAVITY_EARTH);
   634 		}
   668 		}
   635 	}
   669 	}
   636 
       
   637 }
   670 }
   638 
   671