diff options
Diffstat (limited to 'same-android/src/main/java/com/orbekk/same/android')
9 files changed, 942 insertions, 1 deletions
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<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) { + 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<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/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<Player> { + 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> player; + private VariableUpdaterTask<Player> updater; + private AtomicBoolean shouldRedraw = new AtomicBoolean(true); + + private Paint color = new Paint(); + + public GameThread(SurfaceHolder holder, Context context, + Variable<Player> 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>(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<Player> unused) { + logger.info("Variable updated."); + player.update(); + setShouldRedraw(); + } + } + + public GameView(Context context, Variable<Player> 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<GameView.Player>() {}; + Variable<GameView.Player> 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<String, Class<? extends Activity>> activities; + static { + activities = new HashMap<String, Class<? extends Activity>>(); + 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<String> activityList = + new ArrayList<String>(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<? extends Activity> 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<String>( + 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<String> networkNames = new ArrayList<String>(); + private List<String> networkUrls = new ArrayList<String>(); + + 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<String>( + 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<Messenger> stateReceivers = new Vector<Messenger>(); + + 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); + 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<Messenger> dropped = new ArrayList<Messenger>(); + 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<String> contentList = new ArrayList<String>(); + for (State.Component component : client.getState().getComponents()) { + contentList.add(component.toString()); + } + ListView list = (ListView)findViewById(R.id.state_view_list); + list.setAdapter(new ArrayAdapter<String>( + 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<String> variable; + + private Variable.OnChangeListener<String> onChangeListener = + new Variable.OnChangeListener<String>() { + @Override + public void valueChanged(Variable<String> unused) { + variable.update(); + displayVariable(); + } + }; + + private class UpdateVariableTask + extends AsyncTask<String, Void, DelayedOperation.Status> { + @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(); + } +} |