From bc2d8fa1da02037d0b9a2361f394f19e494c8cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kjetil=20=C3=98rbekk?= Date: Mon, 27 Feb 2012 18:16:37 +0100 Subject: Use DelayedOperation on Android. BUGZ --- .../src/main/java/com/orbekk/same/GameView.java | 13 +--- .../src/main/java/com/orbekk/same/SameService.java | 58 +++++++++++++---- .../java/com/orbekk/same/VariableTestActivity.java | 12 ++-- .../orbekk/same/android/ClientInterfaceBridge.java | 76 ++++++++++++++++------ 4 files changed, 110 insertions(+), 49 deletions(-) diff --git a/same-android/src/main/java/com/orbekk/same/GameView.java b/same-android/src/main/java/com/orbekk/same/GameView.java index 527d3da..d9a8052 100644 --- a/same-android/src/main/java/com/orbekk/same/GameView.java +++ b/same-android/src/main/java/com/orbekk/same/GameView.java @@ -51,11 +51,7 @@ public class GameView extends SurfaceView implements SurfaceHolder.Callback { player_.posX = 0.5f; player_.posY = 0.5f; player.setOnChangeListener(this); - try { - player.set(player_); - } catch (UpdateConflict e) { - e.printStackTrace(); - } + player.set(player_); } public void setSize(int width, int height) { @@ -91,12 +87,7 @@ public class GameView extends SurfaceView implements SurfaceHolder.Callback { Player newPlayer = new Player(); newPlayer.posX = x / width; newPlayer.posY = y / width; - try { - player.set(newPlayer); - } catch (UpdateConflict e) { - Toast.makeText(context, "Failed to update position.", - Toast.LENGTH_SHORT).show(); - } + player.set(newPlayer); } @Override diff --git a/same-android/src/main/java/com/orbekk/same/SameService.java b/same-android/src/main/java/com/orbekk/same/SameService.java index 66406bd..3a487d0 100644 --- a/same-android/src/main/java/com/orbekk/same/SameService.java +++ b/same-android/src/main/java/com/orbekk/same/SameService.java @@ -20,16 +20,28 @@ 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 DISPLAY_MESSAGE = 1; public final static int SEARCH_NETWORKS = 2; public final static int CREATE_NETWORK = 3; public final static int JOIN_NETWORK = 4; - public final static int UPDATED_STATE_MESSAGE = 5; - public final static int ADD_STATE_RECEIVER = 6; - public final static int REMOVE_STATE_RECEIVER = 7; - public final static int SET_STATE = 8; + public final static int ADD_STATE_RECEIVER = 5; + public final static int REMOVE_STATE_RECEIVER = 6; + + /** + * arg1: Operation number. + * obj: Updated component. + */ + public final static int SET_STATE = 7; + public final static int UPDATED_STATE_CALLBACK = 8; + + /** + * arg1: Operation number. + * obj: Operation status. + */ + 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 = @@ -113,19 +125,21 @@ public class SameService extends Service { stateReceivers.remove(droppedMessenger); break; case SET_STATE: - // TODO: We may get errors here and we need to inform the - // caller. Perhaps combine with some sort of callback. + logger.info("SET_STATE: oId: {}, comp: {}", message.arg1, message.obj); State.Component updatedComponent = (State.Component)message.obj; - try { - sameController.getClient().getInterface().set( - updatedComponent); - } catch (UpdateConflict e) { - logger.info("Update failed: {}", updatedComponent); - } + int id = message.arg1; + logger.info("Running operation."); + 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."); } } @@ -137,7 +151,7 @@ public class SameService extends Service { synchronized (stateReceivers) { ArrayList dropped = new ArrayList(); for (Messenger messenger : stateReceivers) { - Message message = Message.obtain(null, UPDATED_STATE_MESSAGE); + Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); message.obj = component; try { messenger.send(message); @@ -152,10 +166,26 @@ public class SameService extends Service { } }; + private void operationStatusCallback(DelayedOperation op, int id, Messenger replyTo) { + op.waitFor(); + synchronized (stateReceivers) { + Message message = Message.obtain(null, + OPERATION_STATUS_CALLBACK, id); + message.obj = op.getStatus(); + 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_MESSAGE); + Message message = Message.obtain(null, UPDATED_STATE_CALLBACK); message.obj = c; try { messenger.send(message); diff --git a/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java b/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java index ba33058..1fffbad 100644 --- a/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java +++ b/same-android/src/main/java/com/orbekk/same/VariableTestActivity.java @@ -11,6 +11,7 @@ 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()); @@ -36,12 +37,13 @@ public class VariableTestActivity extends Activity { public void setVariable(View unused) { EditText et = (EditText)findViewById(R.id.set_variable_text); String newValue = et.getText().toString(); - try { - variable.set(newValue); - } catch (UpdateConflict e) { - Toast.makeText(this, "Failed to update.", Toast.LENGTH_SHORT) + logger.info("Setting variable."); + DelayedOperation op = variable.set(newValue); + logger.info("Waiting for delayed operation."); + if (!op.getStatus().isOk()) { + Toast.makeText(this, "Failed to update: " + op.getStatus(), + Toast.LENGTH_SHORT) .show(); - e.printStackTrace(); } } 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 4dde60c..3b490bc 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 @@ -1,6 +1,8 @@ package com.orbekk.same.android; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,11 +24,15 @@ import com.orbekk.same.State.Component; import com.orbekk.same.StateChangedListener; import com.orbekk.same.UpdateConflict; import com.orbekk.same.VariableFactory; +import com.orbekk.util.DelayedOperation; public class ClientInterfaceBridge implements ClientInterface { private State state; private ArrayList listeners = new ArrayList(); + private Map ongoingOperations = + new HashMap(); + private int nextOperationNumber = 0; class ResponseHandler extends Handler { @Override public void handleMessage(Message message) { @@ -35,10 +41,16 @@ public class ClientInterfaceBridge implements ClientInterface { return; } switch (message.what) { - case SameService.UPDATED_STATE_MESSAGE: + case SameService.UPDATED_STATE_CALLBACK: State.Component component = (State.Component)message.obj; updateState(component); break; + case SameService.OPERATION_STATUS_CALLBACK: + int operationNumber = message.arg1; + DelayedOperation.Status status = + (DelayedOperation.Status)message.obj; + completeOperation(operationNumber, status); + break; default: logger.warn("Received unknown message from service: {}", message); @@ -54,14 +66,16 @@ public class ClientInterfaceBridge implements ClientInterface { private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - serviceMessenger = new Messenger(service); - Message message = Message.obtain(null, - SameService.ADD_STATE_RECEIVER); - message.replyTo = responseMessenger; - try { - serviceMessenger.send(message); - } catch (RemoteException e) { - e.printStackTrace(); + synchronized (ClientInterfaceBridge.this) { + serviceMessenger = new Messenger(service); + Message message = Message.obtain(null, + SameService.ADD_STATE_RECEIVER); + message.replyTo = responseMessenger; + try { + serviceMessenger.send(message); + } catch (RemoteException e) { + e.printStackTrace(); + } } } @@ -79,6 +93,22 @@ public class ClientInterfaceBridge implements ClientInterface { } } + private synchronized DelayedOperation createOperation() { + DelayedOperation op = new DelayedOperation(); + op.setIdentifier(nextOperationNumber); + nextOperationNumber += 1; + ongoingOperations.put(op.getIdentifier(), op); + return op; + } + + private synchronized void completeOperation(int operationNumber, + DelayedOperation.Status status) { + DelayedOperation op = ongoingOperations.remove(operationNumber); + if (op != null) { + op.complete(status); + } + } + public ClientInterfaceBridge(Context context) { this.context = context; } @@ -113,24 +143,32 @@ public class ClientInterfaceBridge implements ClientInterface { } @Override - public void set(String name, String data, long revision) throws UpdateConflict { - set(new Component(name, revision, data)); - } - - @Override - public void set(Component component) throws UpdateConflict { - Message message = Message.obtain(null, SameService.SET_STATE); - message.obj = component; + public DelayedOperation set(Component component) { + DelayedOperation op = createOperation(); if (serviceMessenger == null) { logger.warn("Not connected to service. Ignore update: {}", component); - return; + completeOperation(op.getIdentifier(), + DelayedOperation.Status.createError( + "Not connected to service.")); + return op; } + + Message message = Message.obtain(null, SameService.SET_STATE, + op.getIdentifier()); + // this has to be Parcelable. +// message.obj = component; + message.replyTo = responseMessenger; try { + logger.info("Sending update to service."); serviceMessenger.send(message); + logger.info("Service finished update."); } catch (RemoteException e) { e.printStackTrace(); - throw new UpdateConflict(e.getMessage()); + completeOperation(op.getIdentifier(), + DelayedOperation.Status.createError( + "Error contacting service: " + e.getMessage())); } + return op; } @Override -- cgit v1.2.3