summaryrefslogtreecommitdiff
path: root/same-android/src/main/java/com/orbekk/same
diff options
context:
space:
mode:
Diffstat (limited to 'same-android/src/main/java/com/orbekk/same')
-rw-r--r--same-android/src/main/java/com/orbekk/same/GameController.java80
-rw-r--r--same-android/src/main/java/com/orbekk/same/GameView.java120
-rw-r--r--same-android/src/main/java/com/orbekk/same/MainActivity.java31
-rw-r--r--same-android/src/main/java/com/orbekk/same/SameControllerActivity.java131
-rw-r--r--same-android/src/main/java/com/orbekk/same/SameService.java129
5 files changed, 491 insertions, 0 deletions
diff --git a/same-android/src/main/java/com/orbekk/same/GameController.java b/same-android/src/main/java/com/orbekk/same/GameController.java
new file mode 100644
index 0000000..144d6af
--- /dev/null
+++ b/same-android/src/main/java/com/orbekk/same/GameController.java
@@ -0,0 +1,80 @@
+package com.orbekk.same;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.orbekk.same.SameInterface;
+import com.orbekk.same.StateChangedListener;
+import com.orbekk.same.UpdateConflict;
+
+import android.graphics.Paint;
+
+public class GameController implements StateChangedListener {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private List<Player> remotePlayers = new ArrayList<Player>();
+ private Player localPlayer;
+ private ChangeListener changeListener = null;
+ private SameInterface same;
+
+ public static class Player {
+ public Paint color;
+ public float posX;
+ public float posY;
+ }
+
+ public interface ChangeListener {
+ void playerStatesChanged();
+ }
+
+ public static Player newPlayer() {
+ Player player = new Player();
+ player.color = new Paint();
+ player.color.setARGB(255, 255, 0, 0);
+ player.posX = 0.5f;
+ player.posY = 0.5f;
+ return player;
+ }
+
+ public static GameController create(Player localPlayer,
+ SameInterface same) {
+ GameController controller = new GameController(localPlayer, same);
+ same.addStateChangedListener(controller);
+ return controller;
+ }
+
+ GameController(Player localPlayer, SameInterface same) {
+ this.localPlayer = localPlayer;
+ this.same = same;
+ }
+
+ public void setMyPosition(float x, float y) {
+ this.localPlayer.posX = x;
+ this.localPlayer.posY = y;
+ changeListener.playerStatesChanged();
+ try {
+ same.set("position", x + "," + y);
+ } catch (UpdateConflict e) {
+ logger.warn("Update failed.", e);
+ }
+ }
+
+ public Player getLocalPlayer() {
+ return localPlayer;
+ }
+
+ public List<Player> getRemotePlayers() {
+ return remotePlayers;
+ }
+
+ public void setChangeListener(ChangeListener listener) {
+ this.changeListener = listener;
+ }
+
+ @Override
+ public void stateChanged(String id, String data) {
+ logger.info("StateChanged({}, {})", id, data);
+ }
+}
diff --git a/same-android/src/main/java/com/orbekk/same/GameView.java b/same-android/src/main/java/com/orbekk/same/GameView.java
new file mode 100644
index 0000000..b8463d2
--- /dev/null
+++ b/same-android/src/main/java/com/orbekk/same/GameView.java
@@ -0,0 +1,120 @@
+package com.orbekk.same;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.orbekk.same.State.Component;
+import com.orbekk.same.ClientService;
+import com.orbekk.same.Client;
+import com.orbekk.same.SameInterface;
+import com.orbekk.same.UpdateConflict;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public class GameView extends SurfaceView implements SurfaceHolder.Callback {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private GameThread thread;
+
+ static class GameThread extends Thread
+ implements GameController.ChangeListener {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private int height = 0;
+ private int width = 0;
+ private SurfaceHolder holder;
+ private Context context;
+ private Paint background;
+ private GameController controller;
+
+ public GameThread(SurfaceHolder holder, Context context,
+ GameController controller) {
+ this.holder = holder;
+ this.context = context;
+ this.controller = controller;
+ this.controller.setChangeListener(this);
+ background = new Paint();
+ background.setARGB(255, 0, 0, 0);
+ }
+
+ public void setSize(int width, int height) {
+ synchronized(holder) {
+ this.width = width;
+ this.height = height;
+ }
+ }
+
+ private void doDraw(Canvas c) {
+ c.drawRect(0.0f, 0.0f, width+1.0f, height+1.0f, background);
+ for (GameController.Player p : controller.getRemotePlayers()) {
+ c.drawCircle(p.posX * width, p.posY * height, 20.0f, p.color);
+ }
+ GameController.Player localPlayer = controller.getLocalPlayer();
+ c.drawCircle(localPlayer.posX * width, localPlayer.posY * height,
+ 20.0f, localPlayer.color);
+ }
+
+ @Override public void run() {
+ Canvas c = null;
+ try {
+ c = holder.lockCanvas();
+ synchronized(holder) {
+ doDraw(c);
+ }
+ } finally {
+ holder.unlockCanvasAndPost(c);
+ }
+ }
+
+ private synchronized void setPosition(float x, float y) {
+ controller.setMyPosition(x / this.width, y / this.height);
+ }
+
+ @Override
+ public void playerStatesChanged() {
+ run();
+ }
+ }
+
+ public GameView(Context context, GameController controller) {
+ super(context);
+ getHolder().addCallback(this);
+ thread = new GameThread(getHolder(), context, controller);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setARGB(255, 255, 0, 0);
+ canvas.drawCircle(50.0f, 50.0f, 50.0f, paint);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ logger.info("SurfaceChanged(w={}, h={})", width, height);
+ thread.setSize(width, height);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ logger.info("SurfaceCreated()");
+ thread.start();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ logger.info("SurfaceDestroyed()");
+ // TODO: Stop thread.
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent e) {
+ thread.setPosition(e.getX(), e.getY());
+ return true;
+ }
+
+}
diff --git a/same-android/src/main/java/com/orbekk/same/MainActivity.java b/same-android/src/main/java/com/orbekk/same/MainActivity.java
new file mode 100644
index 0000000..49053c8
--- /dev/null
+++ b/same-android/src/main/java/com/orbekk/same/MainActivity.java
@@ -0,0 +1,31 @@
+package com.orbekk.same;
+
+import com.orbekk.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+public class MainActivity extends Activity {
+ @Override public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+
+ @Override public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @Override public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.same_settings) {
+ startActivity(new Intent(this, SameControllerActivity.class));
+ }
+ return true;
+ }
+}
diff --git a/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java b/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java
new file mode 100644
index 0000000..e6bf257
--- /dev/null
+++ b/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java
@@ -0,0 +1,131 @@
+package com.orbekk.same;
+
+import java.util.ArrayList;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.orbekk.R;
+import com.orbekk.same.android.net.Broadcaster;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class SameControllerActivity extends Activity {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private Messenger sameService = null;
+
+ private ServiceConnection sameConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ sameService = new Messenger(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ sameService = null;
+ }
+ };
+
+ private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (SameService.AVAILABLE_NETWORKS_UPDATE.equals(intent.getAction())) {
+ ArrayList<String> networkList = intent.getStringArrayListExtra(
+ SameService.AVAILABLE_NETWORKS);
+ ListView list = (ListView)findViewById(R.id.network_list);
+ list.setAdapter(new ArrayAdapter<String>(
+ SameControllerActivity.this,
+ R.layout.list_text_item, networkList));
+ }
+ }
+ };
+
+ public void createNetwork(View unused) {
+ logger.info("Creating network");
+ Intent intent = new Intent(this, SameService.class);
+ intent.setAction("create");
+ startService(intent);
+ }
+
+ public void joinNetwork(View unused) {
+ logger.info("Joining network");
+ Intent intent = new Intent(this, SameService.class);
+ intent.setAction("join");
+ // InetAddress address = new Broadcaster(this).getBroadcastAddress();
+ EditText t = (EditText)findViewById(R.id.master_service_url);
+ intent.putExtra("masterUrl", t.getText().toString());
+ startService(intent);
+ }
+
+ private void showIpAddress() {
+ TextView t = (TextView)findViewById(R.id.ipAddress);
+ t.setText("My IP: ");
+ t.append(new Broadcaster(this).getWlanAddress().getHostAddress());
+ }
+
+ public void doneClicked(View unused) {
+ finish();
+ }
+
+ public void searchNetworks(View unused) {
+ logger.info("SearchNetworks()");
+ Message searchMessage = Message.obtain(null, SameService.SEARCH_NETWORKS);
+ try {
+ sameService.send(searchMessage);
+ } catch (RemoteException e) {
+ logger.error("Failed to send message", e);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ System.setProperty("java.net.preferIPv4Stack", "true");
+ System.setProperty("java.net.preferIPv6Addresses", "false");
+
+ setContentView(R.layout.controller);
+ showIpAddress();
+ }
+
+ @Override public void onResume() {
+ super.onResume();
+
+ Intent intent = new Intent(this, SameService.class);
+ bindService(intent, sameConnection, Context.BIND_AUTO_CREATE);
+
+ IntentFilter sameServiceUpdates = new IntentFilter(
+ SameService.AVAILABLE_NETWORKS_UPDATE);
+ registerReceiver(broadcastReceiver, sameServiceUpdates);
+ }
+
+ @Override public void onStop() {
+ super.onStop();
+ if (sameService != null) {
+ unbindService(sameConnection);
+ }
+ unregisterReceiver(broadcastReceiver);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+}
+
diff --git a/same-android/src/main/java/com/orbekk/same/SameService.java b/same-android/src/main/java/com/orbekk/same/SameService.java
new file mode 100644
index 0000000..f4cf3e2
--- /dev/null
+++ b/same-android/src/main/java/com/orbekk/same/SameService.java
@@ -0,0 +1,129 @@
+package com.orbekk.same;
+
+import java.util.ArrayList;
+import java.util.Properties;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.widget.Toast;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.orbekk.same.NetworkNotificationListener;
+import com.orbekk.same.SameController;
+import com.orbekk.same.android.net.AndroidBroadcasterFactory;
+import com.orbekk.same.android.net.Broadcaster;
+import com.orbekk.same.config.Configuration;
+
+public class SameService extends Service {
+ public final static int DISPLAY_MESSAGE = 1;
+ public final static int SEARCH_NETWORKS = 2;
+
+ public final static String AVAILABLE_NETWORKS_UPDATE =
+ "com.orbekk.same.SameService.action.AVAILABLE_NETWORKS_UPDATE";
+ public final static String AVAILABLE_NETWORKS =
+ "com.orbekk.same.SameService.action.AVAILABLE_NETWORKS";
+
+ final static int SERVICE_PORT = 15068;
+ final static int DISCOVERY_PORT = 15066;
+
+ private Logger logger = LoggerFactory.getLogger(getClass());
+ private SameController sameController = null;
+ private Configuration configuration = null;
+
+ private ArrayList<String> networkNames = new ArrayList<String>();
+ private ArrayList<String> networkUrls = new ArrayList<String>();
+
+ private NetworkNotificationListener networkListener =
+ new NetworkNotificationListener() {
+ @Override
+ public void notifyNetwork(String networkName, String masterUrl) {
+ logger.info("notifyNetwork({})", networkName);
+ networkNames.add(networkName);
+ networkUrls.add(masterUrl);
+ Intent intent = new Intent(AVAILABLE_NETWORKS_UPDATE);
+ intent.putStringArrayListExtra(AVAILABLE_NETWORKS,
+ networkNames);
+ sendBroadcast(intent);
+ }
+ };
+
+ class InterfaceHandler extends Handler {
+ @Override public void handleMessage(Message message) {
+ switch (message.what) {
+ case DISPLAY_MESSAGE:
+ Toast.makeText(SameService.this,
+ (String)message.obj, Toast.LENGTH_SHORT)
+ .show();
+ break;
+ case SEARCH_NETWORKS:
+ logger.info("SEARCH_NETWORKS");
+ sameController.searchNetworks();
+ break;
+ default:
+ super.handleMessage(message);
+ }
+ }
+ }
+
+ private final Messenger messenger = new Messenger(new InterfaceHandler());
+
+ private void initializeConfiguration() {
+ Properties properties = new Properties();
+ properties.setProperty("port", ""+SERVICE_PORT);
+ properties.setProperty("localIp",
+ new Broadcaster(this).getWlanAddress().getHostAddress());
+ properties.setProperty("masterUrl", "http://10.0.0.6:10010/MasterService.json");
+ properties.setProperty("discoveryPort", ""+DISCOVERY_PORT);
+ configuration = new Configuration(properties);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ logger.info("onBind()");
+
+ // Make sure service continues to run after it is unbound.
+ Intent service = new Intent(this, getClass());
+ startService(service);
+
+ return messenger.getBinder();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ logger.info("onStartCommand()");
+ return START_STICKY;
+ }
+
+ @Override
+ public void onCreate() {
+ logger.info("onCreate()");
+
+ if (sameController == null) {
+ initializeConfiguration();
+ sameController = SameController.create(
+ new AndroidBroadcasterFactory(this),
+ configuration);
+ try {
+ sameController.start();
+ sameController.getClient().setNetworkListener(networkListener);
+ } catch (Exception e) {
+ logger.error("Failed to start server", e);
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ logger.info("onDestroy()");
+ if (sameController != null) {
+ sameController.stop();
+ }
+ }
+
+}