project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
changeset 7508 763d3961400b
parent 7485 0481bd74267c
child 7568 75ba91f14ed5
equal deleted inserted replaced
7504:ed1d52c5aa94 7508:763d3961400b
     1 package org.hedgewars.hedgeroid;
     1 package org.hedgewars.hedgeroid;
       
     2 
       
     3 import java.io.UnsupportedEncodingException;
       
     4 import java.util.concurrent.atomic.AtomicBoolean;
     2 
     5 
     3 import javax.microedition.khronos.egl.EGL10;
     6 import javax.microedition.khronos.egl.EGL10;
     4 import javax.microedition.khronos.egl.EGLConfig;
     7 import javax.microedition.khronos.egl.EGLConfig;
     5 import javax.microedition.khronos.egl.EGLContext;
     8 import javax.microedition.khronos.egl.EGLContext;
     6 import javax.microedition.khronos.egl.EGLDisplay;
     9 import javax.microedition.khronos.egl.EGLDisplay;
    10 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    13 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    11 import org.hedgewars.hedgeroid.frontlib.Flib;
    14 import org.hedgewars.hedgeroid.frontlib.Flib;
    12 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
    15 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
    13 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
    16 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
    14 import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
    17 import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
    15 import org.hedgewars.hedgeroid.netplay.TickHandler;
    18 import org.hedgewars.hedgeroid.netplay.Netplay;
       
    19 import org.hedgewars.hedgeroid.util.FileUtils;
       
    20 import org.hedgewars.hedgeroid.util.TickHandler;
    16 
    21 
    17 import com.sun.jna.Pointer;
    22 import com.sun.jna.Pointer;
    18 
    23 
    19 import android.app.Activity;
    24 import android.app.Activity;
    20 import android.content.Context;
    25 import android.content.Context;
    29 import android.media.AudioTrack;
    34 import android.media.AudioTrack;
    30 import android.os.Bundle;
    35 import android.os.Bundle;
    31 import android.os.Handler;
    36 import android.os.Handler;
    32 import android.os.HandlerThread;
    37 import android.os.HandlerThread;
    33 import android.os.Message;
    38 import android.os.Message;
       
    39 import android.util.Base64;
    34 import android.util.DisplayMetrics;
    40 import android.util.DisplayMetrics;
    35 import android.util.Log;
    41 import android.util.Log;
    36 import android.view.KeyEvent;
    42 import android.view.KeyEvent;
    37 import android.view.MotionEvent;
    43 import android.view.MotionEvent;
    38 import android.view.SurfaceHolder;
    44 import android.view.SurfaceHolder;
    48 	 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all
    54 	 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all
    49 	 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended
    55 	 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended
    50 	 * way to do this (http://developer.android.com/guide/faq/framework.html#3)
    56 	 * way to do this (http://developer.android.com/guide/faq/framework.html#3)
    51 	 */
    57 	 */
    52 	public static volatile GameConfig startConfig;
    58 	public static volatile GameConfig startConfig;
       
    59 	public static volatile boolean startNetgame;
    53 	
    60 	
    54 	// Main components
    61 	// Main components
    55 	public static SDLActivity mSingleton;
    62 	public static SDLActivity mSingleton;
    56 	private static SDLSurface mSurface;
    63 	private static SDLSurface mSurface;
    57 
    64 
    85 
    92 
    86 		// So we can call stuff from static callbacks
    93 		// So we can call stuff from static callbacks
    87 		mSingleton = this;
    94 		mSingleton = this;
    88 
    95 
    89 		// Set up the surface
    96 		// Set up the surface
    90 		mSurface = new SDLSurface(getApplication(), startConfig);
    97 		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
    91 		setContentView(mSurface);
    98 		setContentView(mSurface);
    92 	}
    99 	}
    93 
   100 
    94 	// Events
   101 	// Events
    95 	protected void onPause() {
   102 	protected void onPause() {
   148 		msg.arg1 = command;
   155 		msg.arg1 = command;
   149 		msg.obj = data;
   156 		msg.obj = data;
   150 		commandHandler.sendMessage(msg);
   157 		commandHandler.sendMessage(msg);
   151 	}
   158 	}
   152 
   159 
       
   160 	public static void synchronizedNativeInit(String...args) {
       
   161 		synchronized(PascalExports.engineMutex) {
       
   162 			nativeInit(args);
       
   163 		}
       
   164 	}
       
   165 	
   153 	// C functions we call
   166 	// C functions we call
   154 	public static native void nativeInit(String...args);
   167 	private static native void nativeInit(String...args);
   155 	public static native void nativeQuit();
   168 	public static native void nativeQuit();
   156 	public static native void nativePause();
   169 	public static native void nativePause();
   157 	public static native void nativeResume();
   170 	public static native void nativeResume();
   158 	public static native void onNativeResize(int x, int y, int format);
   171 	public static native void onNativeResize(int x, int y, int format);
   159 	public static native void onNativeKeyDown(int keycode);
   172 	public static native void onNativeKeyDown(int keycode);
   182 
   195 
   183 	public static Context getContext() {
   196 	public static Context getContext() {
   184 		return mSingleton;
   197 		return mSingleton;
   185 	}
   198 	}
   186 
   199 
   187 	public static void startApp(int width, int height, GameConfig config) {
   200 	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
   188 		synchronized(SDLActivity.class) {
   201 		synchronized(SDLActivity.class) {
   189 			// Start up the C app thread
   202 			// Start up the C app thread TODO this is silly code
   190 			if (mSDLThread == null) {
   203 			if (mSDLThread == null) {
   191 				mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread");
   204 				final AtomicBoolean gameconnStartDone = new AtomicBoolean(false);
   192 				mSDLThread.start();
   205 				GameConnection.Listener listener = new GameConnection.Listener() {
       
   206 					public void gameConnectionReady(int port) {
       
   207 						mSDLThread = new Thread(new SDLMain(width, height, port, "Medo"));
       
   208 						mSDLThread.start();
       
   209 						gameconnStartDone.set(true);
       
   210 					}
       
   211 					
       
   212 					public void gameConnectionDisconnected(int reason) {
       
   213 						Log.e("startApp", "disconnected: "+reason);
       
   214 						gameconnStartDone.set(true);
       
   215 					}
       
   216 				};
       
   217 				if(netgame) {
       
   218 					Netplay netplay = Netplay.getAppInstance(mSingleton.getApplicationContext());
       
   219 					GameConnection.forNetgame(config, netplay, listener);
       
   220 				} else {
       
   221 					GameConnection.forLocalGame(config, listener);
       
   222 				}
   193 			} else {
   223 			} else {
   194 				SDLActivity.nativeResume();
   224 				SDLActivity.nativeResume();
   195 			}
   225 			}
   196 		}
   226 		}
   197 	}
   227 	}
   424     Simple nativeInit() runnable
   454     Simple nativeInit() runnable
   425  */
   455  */
   426 class SDLMain implements Runnable {
   456 class SDLMain implements Runnable {
   427 
   457 
   428 	private final int surfaceWidth, surfaceHeight;
   458 	private final int surfaceWidth, surfaceHeight;
   429 	private final GameConfig config;
   459 	private final int port;
   430 	private GameconnPtr conn;
   460 	private final String playerName;
   431 	HandlerThread thread = new HandlerThread("IPC thread");
   461 	HandlerThread thread = new HandlerThread("IPC thread");
   432 	
   462 	
   433 	private final IntCallback dccb = new IntCallback() {
   463 	public SDLMain(int width, int height, int port, String playerName) {
   434 		public void callback(Pointer context, int arg1) {
       
   435 			Log.d("SDLMain", "Disconnected: "+arg1);
       
   436 			Flib.INSTANCE.flib_gameconn_destroy(conn);
       
   437 			conn = null;
       
   438 			thread.quit();
       
   439 		}
       
   440 	};
       
   441 	
       
   442 	public SDLMain(int width, int height, GameConfig _config) {
       
   443 		config = _config;
       
   444 		surfaceWidth = width;
   464 		surfaceWidth = width;
   445 		surfaceHeight = height;
   465 		surfaceHeight = height;
       
   466 		this.port = port;
       
   467 		this.playerName = playerName;
   446 	}
   468 	}
   447 
   469 
   448 	public void run() {
   470 	public void run() {
   449 		//Set up the IPC socket server to communicate with the engine
   471 		//Set up the IPC socket server to communicate with the engine
   450 		
   472 		String path = FileUtils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
   451 		final GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Xeli", GameSetupPtr.createJavaOwned(config), false);
       
   452 		if(conn == null) {
       
   453 			throw new AssertionError();
       
   454 		}
       
   455 		Flib.INSTANCE.flib_gameconn_onDisconnect(conn, dccb, null);
       
   456 		int port = Flib.INSTANCE.flib_gameconn_getport(conn);
       
   457 
       
   458 		String path = Utils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
       
   459 		path = path.substring(0, path.length()-1);//remove the trailing '/'
   473 		path = path.substring(0, path.length()-1);//remove the trailing '/'
   460 
   474 
   461 		thread.start(); // TODO ensure it gets stopped
       
   462 		new TickHandler(thread.getLooper(), 500, new Runnable() {
       
   463 			public void run() {
       
   464 				Log.d("SDLMain", "pre-tick");
       
   465 				Flib.INSTANCE.flib_gameconn_tick(conn);
       
   466 				Log.d("SDLMain", "post-tick");
       
   467 			}
       
   468 		}).start();
       
   469 		
       
   470 		Log.d("SDLMain", "Starting engine");
   475 		Log.d("SDLMain", "Starting engine");
   471 		// Runs SDL_main() with added parameters
   476 		// Runs SDL_main() with added parameters
   472 		SDLActivity.nativeInit(new String[] { String.valueOf(port),
   477 		try {
   473 				String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
   478 			SDLActivity.synchronizedNativeInit(new String[] { String.valueOf(port),
   474 				"0", "en.txt", "xeli", "1", "1", "1", path, ""  });
   479 					String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
       
   480 					"0", "en.txt", Base64.encodeToString(playerName.getBytes("UTF-8"), 0), "1", "1", "1", path, ""  });
       
   481 		} catch (UnsupportedEncodingException e) {
       
   482 			throw new AssertionError(e); // never happens
       
   483 		}
   475 		Log.d("SDLMain", "Engine stopped");
   484 		Log.d("SDLMain", "Engine stopped");
   476 		try {
       
   477 			thread.join();
       
   478 		} catch (InterruptedException e) {
       
   479 			throw new AssertionError();
       
   480 		}
       
   481 		Log.v("SDLMain", "thread joined");
       
   482 		Flib.INSTANCE.flib_gameconn_destroy(conn);
       
   483 		Log.v("SDLMain", "SDL thread terminated");
       
   484 	}
   485 	}
   485 }
   486 }
   486 
   487 
   487 
   488 
   488 /**
   489 /**
   493  */
   494  */
   494 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
   495 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
   495 View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
   496 View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
   496 
   497 
   497 	private GameConfig config;
   498 	private GameConfig config;
   498 
   499 	private boolean netgame;
       
   500 	
   499 	// Sensors
   501 	// Sensors
   500 	private static SensorManager mSensorManager;
   502 	private static SensorManager mSensorManager;
   501 
   503 
   502 	// Startup    
   504 	// Startup    
   503 	public SDLSurface(Context context, GameConfig _config) {
   505 	public SDLSurface(Context context, GameConfig _config, boolean netgame) {
   504 		super(context);
   506 		super(context);
   505 		getHolder().addCallback(this); 
   507 		getHolder().addCallback(this); 
   506 
   508 
   507 		setFocusable(true);
   509 		setFocusable(true);
   508 		setFocusableInTouchMode(true);
   510 		setFocusableInTouchMode(true);
   510 		setOnKeyListener(this); 
   512 		setOnKeyListener(this); 
   511 		setOnTouchListener(this);   
   513 		setOnTouchListener(this);   
   512 
   514 
   513 		mSensorManager = (SensorManager)context.getSystemService("sensor");
   515 		mSensorManager = (SensorManager)context.getSystemService("sensor");
   514 		config = _config;
   516 		config = _config;
       
   517 		this.netgame = netgame;
   515 	}
   518 	}
   516 
   519 
   517 	// Called when we have a valid drawing surface
   520 	// Called when we have a valid drawing surface
   518 	public void surfaceCreated(SurfaceHolder holder) {
   521 	public void surfaceCreated(SurfaceHolder holder) {
   519 		Log.v("SDL", "surfaceCreated()");
   522 		Log.v("SDL", "surfaceCreated()");
   579 			break;
   582 			break;
   580 		}
   583 		}
   581 		SDLActivity.onNativeResize(width, height, sdlFormat);
   584 		SDLActivity.onNativeResize(width, height, sdlFormat);
   582 		Log.v("SDL", "Window size:" + width + "x"+height);
   585 		Log.v("SDL", "Window size:" + width + "x"+height);
   583 
   586 
   584 		SDLActivity.startApp(width, height, config);
   587 		SDLActivity.startApp(width, height, config, netgame);
   585 	}
   588 	}
   586 
   589 
   587 	// unused
   590 	// unused
   588 	public void onDraw(Canvas canvas) {}
   591 	public void onDraw(Canvas canvas) {}
   589 
   592