From 4474ee26b3eee38d1ad33bb3d771d6f804fedfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kjetil=20=C3=98rbekk?= Date: Fri, 2 Mar 2012 16:04:55 +0100 Subject: Move all Android cleasses to com.orbekk.same.android package. --- .../main/java/com/orbekk/same/GameController.java | 72 ------ .../src/main/java/com/orbekk/same/GameView.java | 181 -------------- .../java/com/orbekk/same/GraphicsActivity.java | 38 --- .../main/java/com/orbekk/same/MainActivity.java | 64 ----- .../com/orbekk/same/SameControllerActivity.java | 177 -------------- .../src/main/java/com/orbekk/same/SameService.java | 262 -------------------- .../java/com/orbekk/same/StateViewerActivity.java | 57 ----- .../java/com/orbekk/same/VariableTestActivity.java | 81 ------- .../orbekk/same/android/ClientInterfaceBridge.java | 1 - .../com/orbekk/same/android/GameController.java | 72 ++++++ .../java/com/orbekk/same/android/GameView.java | 185 ++++++++++++++ .../com/orbekk/same/android/GraphicsActivity.java | 38 +++ .../java/com/orbekk/same/android/MainActivity.java | 61 +++++ .../same/android/SameControllerActivity.java | 177 ++++++++++++++ .../java/com/orbekk/same/android/SameService.java | 265 +++++++++++++++++++++ .../orbekk/same/android/StateViewerActivity.java | 59 +++++ .../orbekk/same/android/VariableTestActivity.java | 85 +++++++ 17 files changed, 942 insertions(+), 933 deletions(-) delete mode 100644 same-android/src/main/java/com/orbekk/same/GameController.java delete mode 100644 same-android/src/main/java/com/orbekk/same/GameView.java delete mode 100644 same-android/src/main/java/com/orbekk/same/GraphicsActivity.java delete mode 100644 same-android/src/main/java/com/orbekk/same/MainActivity.java delete mode 100644 same-android/src/main/java/com/orbekk/same/SameControllerActivity.java delete mode 100644 same-android/src/main/java/com/orbekk/same/SameService.java delete mode 100644 same-android/src/main/java/com/orbekk/same/StateViewerActivity.java delete mode 100644 same-android/src/main/java/com/orbekk/same/VariableTestActivity.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/GameController.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/GameView.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/GraphicsActivity.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/MainActivity.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/SameControllerActivity.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/SameService.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/StateViewerActivity.java create mode 100644 same-android/src/main/java/com/orbekk/same/android/VariableTestActivity.java (limited to 'same-android/src/main/java') diff --git a/same-android/src/main/java/com/orbekk/same/GameController.java b/same-android/src/main/java/com/orbekk/same/GameController.java deleted file mode 100644 index b8ea7ad..0000000 --- a/same-android/src/main/java/com/orbekk/same/GameController.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.orbekk.same; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.orbekk.same.StateChangedListener; -import com.orbekk.same.UpdateConflict; - -import android.graphics.Paint; - -public class GameController { - private Logger logger = LoggerFactory.getLogger(getClass()); - private List remotePlayers = new ArrayList(); - 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) { - GameController controller = new GameController(localPlayer); -// same.addStateChangedListener(controller); - return controller; - } - - GameController(Player localPlayer) { - this.localPlayer = localPlayer; - } - - public void setMyPosition(float x, float y) throws UpdateConflict { - this.localPlayer.posX = x; - this.localPlayer.posY = y; - changeListener.playerStatesChanged(); - } - - public Player getLocalPlayer() { - return localPlayer; - } - - public List 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 deleted file mode 100644 index d21d05d..0000000 --- a/same-android/src/main/java/com/orbekk/same/GameView.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.orbekk.same; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -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 Player { - public Player() { - } - public Player(float posX, float posY) { - this.posX = posX; - this.posY = posY; - } - - public float posX; - public float posY; - } - - static class GameThread extends Thread - implements Variable.OnChangeListener { - private Logger logger = LoggerFactory.getLogger(getClass()); - private int height = 0; - private int width = 0; - private SurfaceHolder holder; - private Context context; - private Paint background; - private Variable player; - private VariableUpdaterTask updater; - private AtomicBoolean shouldRedraw = new AtomicBoolean(true); - - private Paint color = new Paint(); - - public GameThread(SurfaceHolder holder, Context context, - Variable player) { - this.holder = holder; - this.context = context; - this.player = player; - background = new Paint(); - background.setARGB(255, 0, 0, 0); - color.setARGB(255, 255, 0, 0); - } - - public void setUp() { - player.addOnChangeListener(this); - updater = new VariableUpdaterTask(player); - updater.set(new Player(0.5f, 0.5f)); - updater.start(); - } - - public void tearDown() { - player.removeOnChangeListener(this); - updater.interrupt(); - } - - 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); - Player player_ = player.get(); - if (player_ == null) { - return; - } - c.drawCircle(player_.posX * width, player_.posY * height, - 20.0f, color); - } - - @Override public void run() { - while (true) { - Canvas c = null; - try { - c = holder.lockCanvas(); - if (c != null) { - synchronized(holder) { - doDraw(c); - } - } - } finally { - if (c != null) { - holder.unlockCanvasAndPost(c); - } - } - synchronized (this) { - if (Thread.interrupted()) { - break; - } - try { - while (!shouldRedraw.get()) { - wait(); - } - } catch (InterruptedException e) { - break; - } - } - } - } - - private synchronized void setShouldRedraw() { - shouldRedraw.set(true); - notifyAll(); - } - - private synchronized void setPosition(final float x, final float y) { - if (player.get() == null || player.get().posX != x || - player.get().posY != y) { - Player newPlayer = new Player(x / width, y / height); - updater.set(newPlayer); - } - } - - @Override - public synchronized void valueChanged(Variable unused) { - logger.info("Variable updated."); - player.update(); - setShouldRedraw(); - } - } - - public GameView(Context context, Variable player) { - super(context); - getHolder().addCallback(this); - thread = new GameThread(getHolder(), context, player); - } - - public void setUp() { - thread.setUp(); - } - - public void tearDown() { - thread.tearDown(); - } - - @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()"); - thread.interrupt(); - } - - @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/GraphicsActivity.java b/same-android/src/main/java/com/orbekk/same/GraphicsActivity.java deleted file mode 100644 index 25a9739..0000000 --- a/same-android/src/main/java/com/orbekk/same/GraphicsActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.orbekk.same; - -import org.codehaus.jackson.type.TypeReference; - -import com.orbekk.same.android.ClientInterfaceBridge; - -import android.app.Activity; -import android.os.Bundle; - -public class GraphicsActivity extends Activity { - private GameView gameView; - private ClientInterfaceBridge client; - - @Override - public void onCreate(Bundle savedBundle) { - super.onCreate(savedBundle); - } - - public void onResume() { - super.onResume(); - client = new ClientInterfaceBridge(this); - client.connect(); - TypeReference playerType = new TypeReference() {}; - Variable player = client.createVariableFactory() - .create("Player", playerType); - gameView = new GameView(this, player); - gameView.setUp(); - setContentView(gameView); - } - - public void onStop() { - super.onStop(); - gameView.tearDown(); - gameView = null; - client.disconnect(); - client = null; - } -} diff --git a/same-android/src/main/java/com/orbekk/same/MainActivity.java b/same-android/src/main/java/com/orbekk/same/MainActivity.java deleted file mode 100644 index e9f7498..0000000 --- a/same-android/src/main/java/com/orbekk/same/MainActivity.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.orbekk.same; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -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.view.View; -import android.widget.Adapter; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import com.orbekk.same.android.benchmark.RepeatedSetVariableActivity; - -public class MainActivity extends Activity { - Logger logger = LoggerFactory.getLogger(getClass()); - - public final static Map> activities; - static { - activities = new HashMap>(); - activities.put("Same settings", SameControllerActivity.class); - activities.put("Variable test", VariableTestActivity.class); - activities.put("State monitor", StateViewerActivity.class); - activities.put("Graphics demo", GraphicsActivity.class); - activities.put("Benchmark", RepeatedSetVariableActivity.class); - } - - public final static List activityList = - new ArrayList(activities.keySet()); - - private AdapterView.OnItemClickListener activityListClickListener = - new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView unused_parent, View unused_view, - int position, long id) { - String activityName = activityList.get(position); - Class activity = activities.get(activityName); - startActivity(new Intent(MainActivity.this, activity)); - } - }; - - private void createActivityList() { - ListView list = (ListView)findViewById(R.id.activities_menu); - list.setAdapter(new ArrayAdapter( - this, R.layout.list_text_item, activityList)); - list.setOnItemClickListener(activityListClickListener); - } - - @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - createActivityList(); - } -} diff --git a/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java b/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java deleted file mode 100644 index 2fb0d25..0000000 --- a/same-android/src/main/java/com/orbekk/same/SameControllerActivity.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.orbekk.same; - -import java.util.List; -import java.util.ArrayList; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.orbekk.same.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.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -public class SameControllerActivity extends Activity { - private Logger logger = LoggerFactory.getLogger(getClass()); - private Messenger sameService = null; - private List networkNames = new ArrayList(); - private List networkUrls = new ArrayList(); - - 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 synchronized void onReceive(Context context, Intent intent) { - if (SameService.AVAILABLE_NETWORKS_UPDATE.equals(intent.getAction())) { - networkNames = intent.getStringArrayListExtra( - SameService.AVAILABLE_NETWORKS); - networkUrls = intent.getStringArrayListExtra( - SameService.NETWORK_URLS); - updateNetworkList(); - } - } - }; - - private AdapterView.OnItemClickListener networkListClickListener = - new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - String networkName = networkNames.get(position); - int networkIndex = networkNames.indexOf(networkName); - String masterUrl = networkUrls.get(networkIndex); - joinNetwork(masterUrl); - } - }; - - private void updateNetworkList() { - ListView list = (ListView)findViewById(R.id.network_list); - list.setAdapter(new ArrayAdapter( - SameControllerActivity.this, - R.layout.list_text_item, networkNames)); - } - - - public void createNetwork(View unused) { - Message message = Message.obtain(null, SameService.CREATE_NETWORK); - try { - sameService.send(message); - } catch (RemoteException e) { - logger.error("Failed to create network", e); - throw new RuntimeException(e); - } - } - - public void joinNetworkUrl(View unused) { - String masterUrl = ""; - Intent intent = new Intent(this, SameService.class); - intent.setAction("join"); - EditText t = (EditText)findViewById(R.id.master_service_url); - masterUrl = t.getText().toString(); - if (!masterUrl.startsWith("http://")) { - masterUrl = "http://" + masterUrl; - } - if (!masterUrl.endsWith("/MasterService.json")) { - masterUrl += "/MasterService.json"; - } - joinNetwork(masterUrl); - } - - private void joinNetwork(String masterUrl) { - logger.info("joinNetwork({})", masterUrl); - Message message = Message.obtain(null, SameService.JOIN_NETWORK); - message.getData().putString("masterUrl", masterUrl); - try { - sameService.send(message); - } catch (RemoteException e) { - logger.error("Failed to send message", e); - throw new RuntimeException(e); - } - } - - 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(); - - ListView networkList = (ListView)findViewById(R.id.network_list); - networkList.setOnItemClickListener(networkListClickListener); - } - - @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 deleted file mode 100644 index f99eb68..0000000 --- a/same-android/src/main/java/com/orbekk/same/SameService.java +++ /dev/null @@ -1,262 +0,0 @@ -package com.orbekk.same; - -import java.util.ArrayList; -import java.util.Properties; -import java.util.Vector; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -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.os.RemoteException; -import android.widget.Toast; - -import com.orbekk.same.State.Component; -import com.orbekk.same.android.ComponentBundle; -import com.orbekk.same.android.net.AndroidBroadcasterFactory; -import com.orbekk.same.android.net.Broadcaster; -import com.orbekk.same.config.Configuration; -import com.orbekk.util.DelayedOperation; - -public class SameService extends Service { - public final static int SEARCH_NETWORKS = 2; - public final static int CREATE_NETWORK = 3; - - /** - * masterUrl: getData().getString("masterUrl") - */ - public final static int JOIN_NETWORK = 4; - public final static int ADD_STATE_RECEIVER = 5; - public final static int REMOVE_STATE_RECEIVER = 6; - - /** - * arg1: Operation number. - * bundle: A Bundle created with ComponentBundle - */ - public final static int SET_STATE = 7; - - /** - * bundle: A Bundle created with ComponentBundle. - */ - public final static int UPDATED_STATE_CALLBACK = 8; - - /** - * arg1: Operation number. - * arg2: Status code. - * obj: Status message. - */ - public final static int OPERATION_STATUS_CALLBACK = 9; - - // TODO: Remove these and use messengers instead of broadcast intents. - 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"; - public final static String NETWORK_URLS = - "com.orbekk.same.SameService.action.NETWORK_URLS"; - - 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 Vector stateReceivers = new Vector(); - - private ArrayList networkNames = new ArrayList(); - private ArrayList networkUrls = new ArrayList(); - - 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); - intent.putStringArrayListExtra(NETWORK_URLS, - networkUrls); - sendBroadcast(intent); - } - }; - - class InterfaceHandler extends Handler { - @Override public void handleMessage(Message message) { - switch (message.what) { - case SEARCH_NETWORKS: - logger.info("SEARCH_NETWORKS"); - sameController.searchNetworks(); - break; - case CREATE_NETWORK: - logger.info("CREATE_NETWORK"); - create(); - break; - case JOIN_NETWORK: - logger.info("JOIN_NETWORK"); - String masterUrl = message.getData().getString("masterUrl"); - sameController.getClient().joinNetwork(masterUrl); - break; - case ADD_STATE_RECEIVER: - logger.info("ADD_STATE_RECEIVER: {}", message); - Messenger messenger = message.replyTo; - if (messenger != null) { - stateReceivers.add(messenger); - sendAllState(messenger); - } else { - logger.error("ADD_STATE_RECEIVER: Missing Messenger."); - } - break; - case REMOVE_STATE_RECEIVER: - logger.info("REMOVE_STATE_RECEIVER: {}", message); - Messenger droppedMessenger = (Messenger)message.obj; - stateReceivers.remove(droppedMessenger); - break; - case SET_STATE: - logger.info("SET_STATE: oId: {}, comp: {}", message.arg1, message.obj); - State.Component updatedComponent = - new ComponentBundle(message.getData()).getComponent(); - int id = message.arg1; - logger.info("Running operation. Component: " + updatedComponent); - DelayedOperation op = sameController.getClient().getInterface() - .set(updatedComponent); - logger.info("Operation finished. Sending callback."); - operationStatusCallback(op, id, message.replyTo); - logger.info("Callback sent."); - break; - default: - super.handleMessage(message); - } - logger.info("Finished handling message."); - } - } - - private final Messenger messenger = new Messenger(new InterfaceHandler()); - - private StateChangedListener stateListener = new StateChangedListener() { - @Override - public void stateChanged(Component component) { - synchronized (stateReceivers) { - ArrayList dropped = new ArrayList(); - for (Messenger messenger : stateReceivers) { - Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); - message.setData(new ComponentBundle(component).getBundle()); - try { - messenger.send(message); - } catch (RemoteException e) { - logger.warn("Failed to send update. Dropping state receiver."); - e.printStackTrace(); - dropped.add(messenger); - } - } - stateReceivers.removeAll(dropped); - } - } - }; - - private void operationStatusCallback(DelayedOperation op, int id, Messenger replyTo) { - op.waitFor(); - synchronized (stateReceivers) { - Message message = Message.obtain(null, - OPERATION_STATUS_CALLBACK); - message.arg1 = id; - message.arg2 = op.getStatus().getStatusCode(); - message.obj = op.getStatus().getMessage(); - try { - messenger.send(message); - } catch (RemoteException e) { - logger.warn("Unable to send update result: " + - op.getStatus()); - e.printStackTrace(); - } - } - } - - private void sendAllState(Messenger messenger) { - State state = sameController.getClient().getInterface().getState(); - for (Component c : state.getComponents()) { - Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); - message.setData(new ComponentBundle(c).getBundle()); - try { - messenger.send(message); - } catch (RemoteException e) { - logger.warn("Failed to send state."); - e.printStackTrace(); - return; - } - } - } - - private void initializeConfiguration() { - Properties properties = new Properties(); - String localIp = new Broadcaster(this) - .getWlanAddress().getHostAddress(); - String localMaster = "http://" + localIp + ":" + SERVICE_PORT + - "/MasterService.json"; - properties.setProperty("port", ""+SERVICE_PORT); - properties.setProperty("localIp", localIp); - properties.setProperty("masterUrl", localMaster); - properties.setProperty("enableDiscovery", "true"); - properties.setProperty("discoveryPort", ""+DISCOVERY_PORT); - properties.setProperty("networkName", "AndroidNetwork"); - configuration = new Configuration(properties); - } - - /** Create a public network. */ - private void create() { - sameController.getClient().joinNetwork( - configuration.get("masterUrl")); - } - - @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_NOT_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); - sameController.getClient().getInterface() - .addStateListener(stateListener); - } catch (Exception e) { - logger.error("Failed to start server", e); - } - } - } - - @Override - public void onDestroy() { - logger.info("onDestroy()"); - if (sameController != null) { - sameController.stop(); - } - } - -} diff --git a/same-android/src/main/java/com/orbekk/same/StateViewerActivity.java b/same-android/src/main/java/com/orbekk/same/StateViewerActivity.java deleted file mode 100644 index a6aa3ee..0000000 --- a/same-android/src/main/java/com/orbekk/same/StateViewerActivity.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.orbekk.same; - -import java.util.ArrayList; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import android.app.Activity; -import android.os.Bundle; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.Toast; - -import com.orbekk.same.State.Component; -import com.orbekk.same.android.ClientInterfaceBridge; - -public class StateViewerActivity extends Activity { - private Logger logger = LoggerFactory.getLogger(getClass()); - private ClientInterfaceBridge client; - - private StateChangedListener stateListener = new StateChangedListener() { - @Override - public void stateChanged(Component component) { - displayState(); - } - }; - - private void displayState() { - ArrayList contentList = new ArrayList(); - for (State.Component component : client.getState().getComponents()) { - contentList.add(component.toString()); - } - ListView list = (ListView)findViewById(R.id.state_view_list); - list.setAdapter(new ArrayAdapter( - this, R.layout.list_text_item, contentList)); - } - - @Override public void onCreate(Bundle bundle) { - super.onCreate(bundle); - setContentView(R.layout.state_viewer); - } - - @Override public void onResume() { - super.onResume(); - client = new ClientInterfaceBridge(this); - client.addStateListener(stateListener); - client.connect(); - } - - @Override public void onStop() { - super.onStop(); - client.removeStateListener(stateListener); - client.disconnect(); - client = null; - } - -} diff --git a/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java b/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java deleted file mode 100644 index 46adb88..0000000 --- a/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.orbekk.same; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import android.app.Activity; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; - -import com.orbekk.same.android.ClientInterfaceBridge; -import com.orbekk.util.DelayedOperation; - -public class VariableTestActivity extends Activity { - private Logger logger = LoggerFactory.getLogger(getClass()); - private ClientInterfaceBridge client; - private Variable variable; - - private Variable.OnChangeListener onChangeListener = - new Variable.OnChangeListener() { - @Override - public void valueChanged(Variable unused) { - variable.update(); - displayVariable(); - } - }; - - private class UpdateVariableTask - extends AsyncTask { - @Override protected DelayedOperation.Status doInBackground(String... values) { - String value = values[0]; - return variable.set(value).getStatus(); - } - - @Override protected void onPostExecute(DelayedOperation.Status status) { - if (!status.isOk()) { - Toast.makeText(VariableTestActivity.this, - "Update failed: " + status, Toast.LENGTH_SHORT) - .show(); - } - } - } - - private void displayVariable() { - TextView tv = (TextView)findViewById(R.id.variable_text); - if (variable.get() != null) { - tv.setText(variable.get()); - } - } - - public void setVariable(View unused) { - EditText et = (EditText)findViewById(R.id.set_variable_text); - String newValue = et.getText().toString(); - new UpdateVariableTask().execute(newValue); - } - - @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.variable_test); - } - - @Override public void onResume() { - super.onResume(); - client = new ClientInterfaceBridge(this); - client.connect(); - variable = client.createVariableFactory() - .createString("TestVariable"); - variable.addOnChangeListener(onChangeListener); - variable.set("Hello, World!"); - displayVariable(); - } - - @Override public void onStop() { - super.onStop(); - variable.removeOnChangeListener(onChangeListener); - client.disconnect(); - } -} diff --git a/same-android/src/main/java/com/orbekk/same/android/ClientInterfaceBridge.java b/same-android/src/main/java/com/orbekk/same/android/ClientInterfaceBridge.java index 72dfdb7..081b7ed 100644 --- a/same-android/src/main/java/com/orbekk/same/android/ClientInterfaceBridge.java +++ b/same-android/src/main/java/com/orbekk/same/android/ClientInterfaceBridge.java @@ -18,7 +18,6 @@ import android.os.Messenger; import android.os.RemoteException; import com.orbekk.same.ClientInterface; -import com.orbekk.same.SameService; import com.orbekk.same.State; import com.orbekk.same.State.Component; import com.orbekk.same.StateChangedListener; diff --git a/same-android/src/main/java/com/orbekk/same/android/GameController.java b/same-android/src/main/java/com/orbekk/same/android/GameController.java new file mode 100644 index 0000000..2678208 --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/GameController.java @@ -0,0 +1,72 @@ +package com.orbekk.same.android; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.orbekk.same.StateChangedListener; +import com.orbekk.same.UpdateConflict; + +import android.graphics.Paint; + +public class GameController { + private Logger logger = LoggerFactory.getLogger(getClass()); + private List remotePlayers = new ArrayList(); + 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) { + GameController controller = new GameController(localPlayer); +// same.addStateChangedListener(controller); + return controller; + } + + GameController(Player localPlayer) { + this.localPlayer = localPlayer; + } + + public void setMyPosition(float x, float y) throws UpdateConflict { + this.localPlayer.posX = x; + this.localPlayer.posY = y; + changeListener.playerStatesChanged(); + } + + public Player getLocalPlayer() { + return localPlayer; + } + + public List 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/android/GameView.java b/same-android/src/main/java/com/orbekk/same/android/GameView.java new file mode 100644 index 0000000..c3485bb --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/GameView.java @@ -0,0 +1,185 @@ +package com.orbekk.same.android; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.orbekk.same.Variable; +import com.orbekk.same.VariableUpdaterTask; +import com.orbekk.same.Variable.OnChangeListener; + +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 Player { + public Player() { + } + public Player(float posX, float posY) { + this.posX = posX; + this.posY = posY; + } + + public float posX; + public float posY; + } + + static class GameThread extends Thread + implements Variable.OnChangeListener { + private Logger logger = LoggerFactory.getLogger(getClass()); + private int height = 0; + private int width = 0; + private SurfaceHolder holder; + private Context context; + private Paint background; + private Variable player; + private VariableUpdaterTask updater; + private AtomicBoolean shouldRedraw = new AtomicBoolean(true); + + private Paint color = new Paint(); + + public GameThread(SurfaceHolder holder, Context context, + Variable player) { + this.holder = holder; + this.context = context; + this.player = player; + background = new Paint(); + background.setARGB(255, 0, 0, 0); + color.setARGB(255, 255, 0, 0); + } + + public void setUp() { + player.addOnChangeListener(this); + updater = new VariableUpdaterTask(player); + updater.set(new Player(0.5f, 0.5f)); + updater.start(); + } + + public void tearDown() { + player.removeOnChangeListener(this); + updater.interrupt(); + } + + 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); + Player player_ = player.get(); + if (player_ == null) { + return; + } + c.drawCircle(player_.posX * width, player_.posY * height, + 20.0f, color); + } + + @Override public void run() { + while (true) { + Canvas c = null; + try { + c = holder.lockCanvas(); + if (c != null) { + synchronized(holder) { + doDraw(c); + } + } + } finally { + if (c != null) { + holder.unlockCanvasAndPost(c); + } + } + synchronized (this) { + if (Thread.interrupted()) { + break; + } + try { + while (!shouldRedraw.get()) { + wait(); + } + } catch (InterruptedException e) { + break; + } + } + } + } + + private synchronized void setShouldRedraw() { + shouldRedraw.set(true); + notifyAll(); + } + + private synchronized void setPosition(final float x, final float y) { + if (player.get() == null || player.get().posX != x || + player.get().posY != y) { + Player newPlayer = new Player(x / width, y / height); + updater.set(newPlayer); + } + } + + @Override + public synchronized void valueChanged(Variable unused) { + logger.info("Variable updated."); + player.update(); + setShouldRedraw(); + } + } + + public GameView(Context context, Variable player) { + super(context); + getHolder().addCallback(this); + thread = new GameThread(getHolder(), context, player); + } + + public void setUp() { + thread.setUp(); + } + + public void tearDown() { + thread.tearDown(); + } + + @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()"); + thread.interrupt(); + } + + @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/android/GraphicsActivity.java b/same-android/src/main/java/com/orbekk/same/android/GraphicsActivity.java new file mode 100644 index 0000000..dab26a7 --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/GraphicsActivity.java @@ -0,0 +1,38 @@ +package com.orbekk.same.android; + +import org.codehaus.jackson.type.TypeReference; + +import com.orbekk.same.Variable; + +import android.app.Activity; +import android.os.Bundle; + +public class GraphicsActivity extends Activity { + private GameView gameView; + private ClientInterfaceBridge client; + + @Override + public void onCreate(Bundle savedBundle) { + super.onCreate(savedBundle); + } + + public void onResume() { + super.onResume(); + client = new ClientInterfaceBridge(this); + client.connect(); + TypeReference playerType = new TypeReference() {}; + Variable player = client.createVariableFactory() + .create("Player", playerType); + gameView = new GameView(this, player); + gameView.setUp(); + setContentView(gameView); + } + + public void onStop() { + super.onStop(); + gameView.tearDown(); + gameView = null; + client.disconnect(); + client = null; + } +} diff --git a/same-android/src/main/java/com/orbekk/same/android/MainActivity.java b/same-android/src/main/java/com/orbekk/same/android/MainActivity.java new file mode 100644 index 0000000..87ec967 --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/MainActivity.java @@ -0,0 +1,61 @@ +package com.orbekk.same.android; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import com.orbekk.same.android.R; +import com.orbekk.same.android.benchmark.RepeatedSetVariableActivity; + +public class MainActivity extends Activity { + Logger logger = LoggerFactory.getLogger(getClass()); + + public final static Map> activities; + static { + activities = new HashMap>(); + activities.put("Same settings", SameControllerActivity.class); + activities.put("Variable test", VariableTestActivity.class); + activities.put("State monitor", StateViewerActivity.class); + activities.put("Graphics demo", GraphicsActivity.class); + activities.put("Benchmark", RepeatedSetVariableActivity.class); + } + + public final static List activityList = + new ArrayList(activities.keySet()); + + private AdapterView.OnItemClickListener activityListClickListener = + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView unused_parent, View unused_view, + int position, long id) { + String activityName = activityList.get(position); + Class activity = activities.get(activityName); + startActivity(new Intent(MainActivity.this, activity)); + } + }; + + private void createActivityList() { + ListView list = (ListView)findViewById(R.id.activities_menu); + list.setAdapter(new ArrayAdapter( + this, R.layout.list_text_item, activityList)); + list.setOnItemClickListener(activityListClickListener); + } + + @Override public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + createActivityList(); + } +} diff --git a/same-android/src/main/java/com/orbekk/same/android/SameControllerActivity.java b/same-android/src/main/java/com/orbekk/same/android/SameControllerActivity.java new file mode 100644 index 0000000..7700e2f --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/SameControllerActivity.java @@ -0,0 +1,177 @@ +package com.orbekk.same.android; + +import java.util.List; +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.orbekk.same.android.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.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +public class SameControllerActivity extends Activity { + private Logger logger = LoggerFactory.getLogger(getClass()); + private Messenger sameService = null; + private List networkNames = new ArrayList(); + private List networkUrls = new ArrayList(); + + 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 synchronized void onReceive(Context context, Intent intent) { + if (SameService.AVAILABLE_NETWORKS_UPDATE.equals(intent.getAction())) { + networkNames = intent.getStringArrayListExtra( + SameService.AVAILABLE_NETWORKS); + networkUrls = intent.getStringArrayListExtra( + SameService.NETWORK_URLS); + updateNetworkList(); + } + } + }; + + private AdapterView.OnItemClickListener networkListClickListener = + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String networkName = networkNames.get(position); + int networkIndex = networkNames.indexOf(networkName); + String masterUrl = networkUrls.get(networkIndex); + joinNetwork(masterUrl); + } + }; + + private void updateNetworkList() { + ListView list = (ListView)findViewById(R.id.network_list); + list.setAdapter(new ArrayAdapter( + SameControllerActivity.this, + R.layout.list_text_item, networkNames)); + } + + + public void createNetwork(View unused) { + Message message = Message.obtain(null, SameService.CREATE_NETWORK); + try { + sameService.send(message); + } catch (RemoteException e) { + logger.error("Failed to create network", e); + throw new RuntimeException(e); + } + } + + public void joinNetworkUrl(View unused) { + String masterUrl = ""; + Intent intent = new Intent(this, SameService.class); + intent.setAction("join"); + EditText t = (EditText)findViewById(R.id.master_service_url); + masterUrl = t.getText().toString(); + if (!masterUrl.startsWith("http://")) { + masterUrl = "http://" + masterUrl; + } + if (!masterUrl.endsWith("/MasterService.json")) { + masterUrl += "/MasterService.json"; + } + joinNetwork(masterUrl); + } + + private void joinNetwork(String masterUrl) { + logger.info("joinNetwork({})", masterUrl); + Message message = Message.obtain(null, SameService.JOIN_NETWORK); + message.getData().putString("masterUrl", masterUrl); + try { + sameService.send(message); + } catch (RemoteException e) { + logger.error("Failed to send message", e); + throw new RuntimeException(e); + } + } + + 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(); + + ListView networkList = (ListView)findViewById(R.id.network_list); + networkList.setOnItemClickListener(networkListClickListener); + } + + @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/android/SameService.java b/same-android/src/main/java/com/orbekk/same/android/SameService.java new file mode 100644 index 0000000..f5116ba --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/SameService.java @@ -0,0 +1,265 @@ +package com.orbekk.same.android; + +import java.util.ArrayList; +import java.util.Properties; +import java.util.Vector; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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.os.RemoteException; +import android.widget.Toast; + +import com.orbekk.same.NetworkNotificationListener; +import com.orbekk.same.SameController; +import com.orbekk.same.State; +import com.orbekk.same.StateChangedListener; +import com.orbekk.same.State.Component; +import com.orbekk.same.android.net.AndroidBroadcasterFactory; +import com.orbekk.same.android.net.Broadcaster; +import com.orbekk.same.config.Configuration; +import com.orbekk.util.DelayedOperation; + +public class SameService extends Service { + public final static int SEARCH_NETWORKS = 2; + public final static int CREATE_NETWORK = 3; + + /** + * masterUrl: getData().getString("masterUrl") + */ + public final static int JOIN_NETWORK = 4; + public final static int ADD_STATE_RECEIVER = 5; + public final static int REMOVE_STATE_RECEIVER = 6; + + /** + * arg1: Operation number. + * bundle: A Bundle created with ComponentBundle + */ + public final static int SET_STATE = 7; + + /** + * bundle: A Bundle created with ComponentBundle. + */ + public final static int UPDATED_STATE_CALLBACK = 8; + + /** + * arg1: Operation number. + * arg2: Status code. + * obj: Status message. + */ + public final static int OPERATION_STATUS_CALLBACK = 9; + + // TODO: Remove these and use messengers instead of broadcast intents. + 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"; + public final static String NETWORK_URLS = + "com.orbekk.same.SameService.action.NETWORK_URLS"; + + 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 Vector stateReceivers = new Vector(); + + private ArrayList networkNames = new ArrayList(); + private ArrayList networkUrls = new ArrayList(); + + 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); + intent.putStringArrayListExtra(NETWORK_URLS, + networkUrls); + sendBroadcast(intent); + } + }; + + class InterfaceHandler extends Handler { + @Override public void handleMessage(Message message) { + switch (message.what) { + case SEARCH_NETWORKS: + logger.info("SEARCH_NETWORKS"); + sameController.searchNetworks(); + break; + case CREATE_NETWORK: + logger.info("CREATE_NETWORK"); + create(); + break; + case JOIN_NETWORK: + logger.info("JOIN_NETWORK"); + String masterUrl = message.getData().getString("masterUrl"); + sameController.getClient().joinNetwork(masterUrl); + break; + case ADD_STATE_RECEIVER: + logger.info("ADD_STATE_RECEIVER: {}", message); + Messenger messenger = message.replyTo; + if (messenger != null) { + stateReceivers.add(messenger); + sendAllState(messenger); + } else { + logger.error("ADD_STATE_RECEIVER: Missing Messenger."); + } + break; + case REMOVE_STATE_RECEIVER: + logger.info("REMOVE_STATE_RECEIVER: {}", message); + Messenger droppedMessenger = (Messenger)message.obj; + stateReceivers.remove(droppedMessenger); + break; + case SET_STATE: + logger.info("SET_STATE: oId: {}, comp: {}", message.arg1, message.obj); + State.Component updatedComponent = + new ComponentBundle(message.getData()).getComponent(); + int id = message.arg1; + logger.info("Running operation. Component: " + updatedComponent); + DelayedOperation op = sameController.getClient().getInterface() + .set(updatedComponent); + logger.info("Operation finished. Sending callback."); + operationStatusCallback(op, id, message.replyTo); + logger.info("Callback sent."); + break; + default: + super.handleMessage(message); + } + logger.info("Finished handling message."); + } + } + + private final Messenger messenger = new Messenger(new InterfaceHandler()); + + private StateChangedListener stateListener = new StateChangedListener() { + @Override + public void stateChanged(Component component) { + synchronized (stateReceivers) { + ArrayList dropped = new ArrayList(); + for (Messenger messenger : stateReceivers) { + Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); + message.setData(new ComponentBundle(component).getBundle()); + try { + messenger.send(message); + } catch (RemoteException e) { + logger.warn("Failed to send update. Dropping state receiver."); + e.printStackTrace(); + dropped.add(messenger); + } + } + stateReceivers.removeAll(dropped); + } + } + }; + + private void operationStatusCallback(DelayedOperation op, int id, Messenger replyTo) { + op.waitFor(); + synchronized (stateReceivers) { + Message message = Message.obtain(null, + OPERATION_STATUS_CALLBACK); + message.arg1 = id; + message.arg2 = op.getStatus().getStatusCode(); + message.obj = op.getStatus().getMessage(); + try { + messenger.send(message); + } catch (RemoteException e) { + logger.warn("Unable to send update result: " + + op.getStatus()); + e.printStackTrace(); + } + } + } + + private void sendAllState(Messenger messenger) { + State state = sameController.getClient().getInterface().getState(); + for (Component c : state.getComponents()) { + Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); + message.setData(new ComponentBundle(c).getBundle()); + try { + messenger.send(message); + } catch (RemoteException e) { + logger.warn("Failed to send state."); + e.printStackTrace(); + return; + } + } + } + + private void initializeConfiguration() { + Properties properties = new Properties(); + String localIp = new Broadcaster(this) + .getWlanAddress().getHostAddress(); + String localMaster = "http://" + localIp + ":" + SERVICE_PORT + + "/MasterService.json"; + properties.setProperty("port", ""+SERVICE_PORT); + properties.setProperty("localIp", localIp); + properties.setProperty("masterUrl", localMaster); + properties.setProperty("enableDiscovery", "true"); + properties.setProperty("discoveryPort", ""+DISCOVERY_PORT); + properties.setProperty("networkName", "AndroidNetwork"); + configuration = new Configuration(properties); + } + + /** Create a public network. */ + private void create() { + sameController.getClient().joinNetwork( + configuration.get("masterUrl")); + } + + @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_NOT_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); + sameController.getClient().getInterface() + .addStateListener(stateListener); + } catch (Exception e) { + logger.error("Failed to start server", e); + } + } + } + + @Override + public void onDestroy() { + logger.info("onDestroy()"); + if (sameController != null) { + sameController.stop(); + } + } + +} diff --git a/same-android/src/main/java/com/orbekk/same/android/StateViewerActivity.java b/same-android/src/main/java/com/orbekk/same/android/StateViewerActivity.java new file mode 100644 index 0000000..679e3b6 --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/StateViewerActivity.java @@ -0,0 +1,59 @@ +package com.orbekk.same.android; + +import java.util.ArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.Toast; + +import com.orbekk.same.android.R; +import com.orbekk.same.State; +import com.orbekk.same.StateChangedListener; +import com.orbekk.same.State.Component; + +public class StateViewerActivity extends Activity { + private Logger logger = LoggerFactory.getLogger(getClass()); + private ClientInterfaceBridge client; + + private StateChangedListener stateListener = new StateChangedListener() { + @Override + public void stateChanged(Component component) { + displayState(); + } + }; + + private void displayState() { + ArrayList contentList = new ArrayList(); + for (State.Component component : client.getState().getComponents()) { + contentList.add(component.toString()); + } + ListView list = (ListView)findViewById(R.id.state_view_list); + list.setAdapter(new ArrayAdapter( + this, R.layout.list_text_item, contentList)); + } + + @Override public void onCreate(Bundle bundle) { + super.onCreate(bundle); + setContentView(R.layout.state_viewer); + } + + @Override public void onResume() { + super.onResume(); + client = new ClientInterfaceBridge(this); + client.addStateListener(stateListener); + client.connect(); + } + + @Override public void onStop() { + super.onStop(); + client.removeStateListener(stateListener); + client.disconnect(); + client = null; + } + +} diff --git a/same-android/src/main/java/com/orbekk/same/android/VariableTestActivity.java b/same-android/src/main/java/com/orbekk/same/android/VariableTestActivity.java new file mode 100644 index 0000000..7560a41 --- /dev/null +++ b/same-android/src/main/java/com/orbekk/same/android/VariableTestActivity.java @@ -0,0 +1,85 @@ +package com.orbekk.same.android; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.app.Activity; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.orbekk.same.android.R; +import com.orbekk.same.Variable; +import com.orbekk.same.android.R.id; +import com.orbekk.same.android.R.layout; +import com.orbekk.same.Variable.OnChangeListener; +import com.orbekk.util.DelayedOperation; + +public class VariableTestActivity extends Activity { + private Logger logger = LoggerFactory.getLogger(getClass()); + private ClientInterfaceBridge client; + private Variable variable; + + private Variable.OnChangeListener onChangeListener = + new Variable.OnChangeListener() { + @Override + public void valueChanged(Variable unused) { + variable.update(); + displayVariable(); + } + }; + + private class UpdateVariableTask + extends AsyncTask { + @Override protected DelayedOperation.Status doInBackground(String... values) { + String value = values[0]; + return variable.set(value).getStatus(); + } + + @Override protected void onPostExecute(DelayedOperation.Status status) { + if (!status.isOk()) { + Toast.makeText(VariableTestActivity.this, + "Update failed: " + status, Toast.LENGTH_SHORT) + .show(); + } + } + } + + private void displayVariable() { + TextView tv = (TextView)findViewById(R.id.variable_text); + if (variable.get() != null) { + tv.setText(variable.get()); + } + } + + public void setVariable(View unused) { + EditText et = (EditText)findViewById(R.id.set_variable_text); + String newValue = et.getText().toString(); + new UpdateVariableTask().execute(newValue); + } + + @Override public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.variable_test); + } + + @Override public void onResume() { + super.onResume(); + client = new ClientInterfaceBridge(this); + client.connect(); + variable = client.createVariableFactory() + .createString("TestVariable"); + variable.addOnChangeListener(onChangeListener); + variable.set("Hello, World!"); + displayVariable(); + } + + @Override public void onStop() { + super.onStop(); + variable.removeOnChangeListener(onChangeListener); + client.disconnect(); + } +} -- cgit v1.2.3