Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Comminos <andrew@comminos.com>2015-10-19 09:02:29 +0300
committerAndrew Comminos <andrew@comminos.com>2015-10-19 09:02:29 +0300
commit523e9357752a68024e1525a8354a804d76eedf5f (patch)
tree10e42a12686a025bd3800e40956e84e06a86ba13
parentb6bac053a8e45768b9c75463d01e9610f5474663 (diff)
Expose Jumble API through JumbleBinder instead of AIDL. Add public interfaces for exposing Jumble internal types.
-rw-r--r--src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java7
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleBinder.java412
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleService.java551
-rw-r--r--src/main/java/com/morlunk/jumble/model/Channel.java13
-rw-r--r--src/main/java/com/morlunk/jumble/model/IChannel.java44
-rw-r--r--src/main/java/com/morlunk/jumble/model/IMessage.java36
-rw-r--r--src/main/java/com/morlunk/jumble/model/IUser.java61
-rw-r--r--src/main/java/com/morlunk/jumble/model/Message.java9
-rw-r--r--src/main/java/com/morlunk/jumble/model/User.java21
-rw-r--r--src/main/java/com/morlunk/jumble/net/JumbleConnection.java18
-rw-r--r--src/main/java/com/morlunk/jumble/protocol/ModelHandler.java66
-rw-r--r--src/main/java/com/morlunk/jumble/util/IJumbleObserver.java65
-rw-r--r--src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java186
-rw-r--r--src/main/java/com/morlunk/jumble/util/JumbleObserver.java49
-rw-r--r--src/main/java/com/morlunk/jumble/util/ParcelableByteArray.java67
15 files changed, 901 insertions, 704 deletions
diff --git a/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java b/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java
index e4f0d68..d309f55 100644
--- a/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java
+++ b/src/androidTest/java/com/morlunk/jumble/test/JumbleServiceTest.java
@@ -21,7 +21,7 @@ import android.content.Intent;
import android.os.RemoteException;
import android.test.ServiceTestCase;
-import com.morlunk.jumble.IJumbleService;
+import com.morlunk.jumble.JumbleBinder;
import com.morlunk.jumble.JumbleService;
import com.morlunk.jumble.model.Server;
@@ -45,11 +45,10 @@ public class JumbleServiceTest extends ServiceTestCase<JumbleService> {
intent.putExtra(JumbleService.EXTRAS_SERVER, DUMMY_SERVER);
startService(intent);
JumbleService service = getService();
- IJumbleService binder = service.getBinder();
+ JumbleBinder binder = (JumbleBinder) service.onBind(intent);
assertFalse(binder.isReconnecting());
assertNull(binder.getConnectionError());
- assertEquals(JumbleService.STATE_DISCONNECTED, binder.getConnectionState());
- assertFalse(binder.isTalking());
+ assertEquals(JumbleService.ConnectionState.DISCONNECTED, binder.getConnectionState());
assertEquals(DUMMY_SERVER, binder.getConnectedServer());
}
diff --git a/src/main/java/com/morlunk/jumble/JumbleBinder.java b/src/main/java/com/morlunk/jumble/JumbleBinder.java
new file mode 100644
index 0000000..b0db425
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/JumbleBinder.java
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2015 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble;
+
+import android.os.Binder;
+import android.util.Log;
+
+import com.morlunk.jumble.exception.AudioException;
+import com.morlunk.jumble.model.Channel;
+import com.morlunk.jumble.model.IChannel;
+import com.morlunk.jumble.model.IUser;
+import com.morlunk.jumble.model.Message;
+import com.morlunk.jumble.model.Server;
+import com.morlunk.jumble.model.User;
+import com.morlunk.jumble.net.JumbleConnection;
+import com.morlunk.jumble.net.JumbleTCPMessageType;
+import com.morlunk.jumble.net.JumbleUDPMessageType;
+import com.morlunk.jumble.protobuf.Mumble;
+import com.morlunk.jumble.util.IJumbleObserver;
+import com.morlunk.jumble.util.JumbleException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A public interface for clients to communicate with a {@link JumbleService}.
+ * The long-term goal for this class is to migrate of the complexity out of this class into a
+ * JumbleProtocol class that is owned by a {@link com.morlunk.jumble.net.JumbleConnection}.
+ * <br><br>
+ * Calls are not guaranteed to be thread-safe, so only call the binder from the main thread.
+ * Service state changes related to connection state are only guaranteed to work if isConnected()
+ * is checked to be true.
+ * <br><br>
+ * If not explicitly stated in the method documentation, any call that depends on connection state
+ * will throw IllegalStateException if disconnected or not synchronized.
+ */
+public class JumbleBinder extends Binder {
+ private final JumbleService mService;
+
+ protected JumbleBinder(JumbleService service) {
+ mService = service;
+ }
+
+ /**
+ * Returns the current connection state of the service.
+ * @return one of {@link com.morlunk.jumble.JumbleService.ConnectionState}.
+ */
+ public JumbleService.ConnectionState getConnectionState() {
+ return mService.getConnectionState();
+ }
+
+ /**
+ * If the {@link JumbleService} disconnected due to an error, returns that error.
+ * @return The error causing disconnection. If the last disconnection was successful or a
+ * connection has yet to be established, returns null.
+ */
+ public JumbleException getConnectionError() {
+ JumbleConnection connection = mService.getConnection();
+ return connection != null ? connection.getError() : null;
+ }
+
+ /**
+ * Returns the reconnection state of the {@link JumbleService}.
+ * @return true if the service will attempt to automatically reconnect in the future.
+ */
+ public boolean isReconnecting() {
+ return mService.isReconnecting();
+ }
+
+ /**
+ * Cancels any future reconnection attempts. Does nothing if reconnection is not in progress.
+ */
+ public void cancelReconnect() {
+ mService.setReconnecting(false);
+ }
+
+ /**
+ * @return the latency in milliseconds for the TCP connection.
+ * @throws IllegalStateException if not connected.
+ */
+ public long getTCPLatency() {
+ return mService.getConnection().getTCPLatency();
+ }
+
+ /**
+ * @return the latency in milliseconds for the UDP connection.
+ * @throws IllegalStateException if not connected.
+ */
+ public long getUDPLatency() {
+ return mService.getConnection().getUDPLatency();
+ }
+
+ /**
+ * @return the maximum bandwidth in bps for audio allowed by the server, or -1 if not set.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public int getMaxBandwidth() {
+ return mService.getConnection().getMaxBandwidth();
+ }
+
+ /**
+ * @return the current bandwidth in bps for audio sent to the server, or a negative integer
+ * if unknown (prior to connection or after disconnection).
+ * @throws IllegalStateException if not synchronized.
+ */
+ public int getCurrentBandwidth() {
+ return mService.getAudioHandler().getCurrentBandwidth();
+ }
+
+ /**
+ * Returns the protocol version returned by the server in the format 0xAABBCC, where AA
+ * indicates the major version, BB indicates the minor version, and CC indicates the patch
+ * version. This is the same formatting used by the Mumble protocol in big-endian format.
+ * @return the current bandwidth in bps for audio sent to the server, or a negative integer
+ * if unknown (prior to connection or after disconnection).
+ * @throws IllegalStateException if not synchronized.
+ */
+ public int getServerVersion() {
+ return mService.getConnection().getServerVersion();
+ }
+
+ /**
+ * @return a user-readable string with the server's Mumble release info.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public String getServerRelease() {
+ return mService.getConnection().getServerRelease();
+ }
+
+ /**
+ * @return a user-readable string with the server's OS name.
+ * @throws IllegalStateException if not connected.
+ */
+ public String getServerOSName() {
+ return mService.getConnection().getServerOSName();
+ }
+
+ /**
+ * @return a user-readable string with the server's OS version.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public String getServerOSVersion() {
+ return mService.getConnection().getServerOSVersion();
+ }
+
+ /**
+ * Returns the current user's session. Set during server synchronization.
+ * @return an integer identifying the current user's connection.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public int getSession() {
+ return mService.getConnection().getSession();
+ }
+
+ /**
+ * Returns the current user. Set during server synchronization.
+ * @return the {@link IUser} representing the current user.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public IUser getSessionUser() {
+ return mService.getModelHandler().getUser(getSession());
+ }
+
+ /**
+ * Returns the user's current channel.
+ * @return the {@link IChannel} representing the user's current channel.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public IChannel getSessionChannel() {
+ IUser user = getSessionUser();
+ if (user != null)
+ return user.getChannel();
+ throw new IllegalStateException("Session user should be set post-synchronization!");
+ }
+
+ /**
+ * @return the server that Jumble is currently connected to (or attempted connection to).
+ */
+ public Server getConnectedServer() {
+ return mService.getConnectedServer();
+ }
+
+ /**
+ * Retrieves the user with the given session ID.
+ * @param session An integer ID identifying a user's session. See {@link IUser#getSession()}.
+ * @return A user with the given session, or null if not found.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public IUser getUser(int session) {
+ return mService.getModelHandler().getUser(session);
+ }
+
+ /**
+ * Retrieves the channel with the given ID.
+ * @param id An integer ID identifying a channel. See {@link IChannel#getId()}.
+ * @return A channel with the given session, or null if not found.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public IChannel getChannel(int id) {
+ return mService.getModelHandler().getChannel(id);
+ }
+
+ /**
+ * @return the root channel of the server.
+ * @throws IllegalStateException if not synchronized.
+ */
+ public IChannel getRootChannel() {
+ return getChannel(0);
+ }
+
+ public int getPermissions() {
+ return mService.getModelHandler().getPermissions();
+ }
+
+ public int getTransmitMode() {
+ return mService.getAudioHandler().getTransmitMode();
+ }
+
+ public JumbleUDPMessageType getCodec() {
+ return mService.getConnection().getCodec();
+ }
+
+ public boolean usingBluetoothSco() {
+ return mService.getBluetoothReceiver().isBluetoothScoOn();
+ }
+
+ public void enableBluetoothSco() {
+ mService.getBluetoothReceiver().startBluetoothSco();
+ }
+
+ public void disableBluetoothSco() {
+ mService.getBluetoothReceiver().stopBluetoothSco();
+ }
+
+ public boolean isTalking() {
+ return mService.getAudioHandler().isRecording();
+ }
+
+ public void setTalkingState(boolean talking) {
+ if (getSessionUser().isSelfMuted() || getSessionUser().isMuted())
+ return;
+
+ if (mService.getAudioHandler().getTransmitMode() != Constants.TRANSMIT_PUSH_TO_TALK) {
+ Log.w(Constants.TAG, "Attempted to set talking state when not using PTT");
+ return;
+ }
+
+ try {
+ mService.getAudioHandler().setTalking(talking);
+ } catch (AudioException e) {
+ mService.logError(e.getMessage());
+ }
+ }
+
+ public void joinChannel(int channel) {
+ moveUserToChannel(getSession(), channel);
+ }
+
+ public void moveUserToChannel(int session, int channel) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSession(session);
+ usb.setChannelId(channel);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void createChannel(int parent, String name, String description, int position, boolean temporary) {
+ Mumble.ChannelState.Builder csb = Mumble.ChannelState.newBuilder();
+ csb.setParent(parent);
+ csb.setName(name);
+ csb.setDescription(description);
+ csb.setPosition(position);
+ csb.setTemporary(temporary);
+ mService.getConnection().sendTCPMessage(csb.build(), JumbleTCPMessageType.ChannelState);
+ }
+
+ public void sendAccessTokens(final List<String> tokens) {
+ mService.getConnection().sendAccessTokens(tokens);
+ }
+
+ public void requestBanList() {
+ throw new UnsupportedOperationException("Not yet implemented"); // TODO
+ }
+
+ public void requestUserList() {
+ throw new UnsupportedOperationException("Not yet implemented"); // TODO
+ }
+
+ public void requestPermissions(int channel) {
+ Mumble.PermissionQuery.Builder pqb = Mumble.PermissionQuery.newBuilder();
+ pqb.setChannelId(channel);
+ mService.getConnection().sendTCPMessage(pqb.build(), JumbleTCPMessageType.PermissionQuery);
+ }
+
+ public void requestComment(int session) {
+ Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
+ rbb.addSessionComment(session);
+ mService.getConnection().sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
+ }
+
+ public void requestAvatar(int session) {
+ Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
+ rbb.addSessionTexture(session);
+ mService.getConnection().sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
+ }
+
+ public void requestChannelDescription(int channel) {
+ Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
+ rbb.addChannelDescription(channel);
+ mService.getConnection().sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
+ }
+
+ public void registerUser(int session) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSession(session);
+ usb.setUserId(0);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void kickBanUser(int session, String reason, boolean ban) {
+ Mumble.UserRemove.Builder urb = Mumble.UserRemove.newBuilder();
+ urb.setSession(session);
+ urb.setReason(reason);
+ urb.setBan(ban);
+ mService.getConnection().sendTCPMessage(urb.build(), JumbleTCPMessageType.UserRemove);
+ }
+
+ public Message sendUserTextMessage(int session, String message) {
+ Mumble.TextMessage.Builder tmb = Mumble.TextMessage.newBuilder();
+ tmb.addSession(session);
+ tmb.setMessage(message);
+ mService.getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage);
+
+ User self = mService.getModelHandler().getUser(getSession());
+ User user = mService.getModelHandler().getUser(session);
+ List<User> users = new ArrayList<User>(1);
+ users.add(user);
+ return new Message(getSession(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message);
+ }
+
+ public Message sendChannelTextMessage(int channel, String message, boolean tree) {
+ Mumble.TextMessage.Builder tmb = Mumble.TextMessage.newBuilder();
+ if(tree) tmb.addTreeId(channel);
+ else tmb.addChannelId(channel);
+ tmb.setMessage(message);
+ mService.getConnection().sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage);
+
+ User self = mService.getModelHandler().getUser(getSession());
+ Channel targetChannel = mService.getModelHandler().getChannel(channel);
+ List<Channel> targetChannels = new ArrayList<Channel>();
+ targetChannels.add(targetChannel);
+ return new Message(getSession(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message);
+ }
+
+ public void setUserComment(int session, String comment) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSession(session);
+ usb.setComment(comment);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void setPrioritySpeaker(int session, boolean priority) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSession(session);
+ usb.setPrioritySpeaker(priority);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void removeChannel(int channel) {
+ Mumble.ChannelRemove.Builder crb = Mumble.ChannelRemove.newBuilder();
+ crb.setChannelId(channel);
+ mService.getConnection().sendTCPMessage(crb.build(), JumbleTCPMessageType.ChannelRemove);
+ }
+
+ public void setMuteDeafState(int session, boolean mute, boolean deaf) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSession(session);
+ usb.setMute(mute);
+ usb.setDeaf(deaf);
+ if (!mute) usb.setSuppress(false);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void setSelfMuteDeafState(boolean mute, boolean deaf) {
+ Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
+ usb.setSelfMute(mute);
+ usb.setSelfDeaf(deaf);
+ mService.getConnection().sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
+ }
+
+ public void registerObserver(IJumbleObserver observer) {
+ mService.registerObserver(observer);
+ }
+
+ public void unregisterObserver(IJumbleObserver observer) {
+ mService.unregisterObserver(observer);
+ }
+}
diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java
index 63e4b3c..4d358f0 100644
--- a/src/main/java/com/morlunk/jumble/JumbleService.java
+++ b/src/main/java/com/morlunk/jumble/JumbleService.java
@@ -30,20 +30,16 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
-import android.os.RemoteException;
import android.util.Log;
import com.morlunk.jumble.audio.AudioOutput;
import com.morlunk.jumble.audio.BluetoothScoReceiver;
import com.morlunk.jumble.exception.AudioException;
-import com.morlunk.jumble.model.Channel;
-import com.morlunk.jumble.model.IChannel;
-import com.morlunk.jumble.model.IUser;
-import com.morlunk.jumble.model.Message;
import com.morlunk.jumble.model.Server;
import com.morlunk.jumble.model.TalkState;
import com.morlunk.jumble.model.User;
import com.morlunk.jumble.net.JumbleConnection;
+import com.morlunk.jumble.util.IJumbleObserver;
import com.morlunk.jumble.util.JumbleException;
import com.morlunk.jumble.net.JumbleTCPMessageType;
import com.morlunk.jumble.protobuf.Mumble;
@@ -51,12 +47,9 @@ import com.morlunk.jumble.protocol.AudioHandler;
import com.morlunk.jumble.protocol.ModelHandler;
import com.morlunk.jumble.util.JumbleCallbacks;
import com.morlunk.jumble.util.JumbleLogger;
-import com.morlunk.jumble.util.ParcelableByteArray;
import java.security.Security;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.List;
public class JumbleService extends Service implements JumbleConnection.JumbleConnectionListener, JumbleLogger, BluetoothScoReceiver.Listener {
@@ -67,27 +60,6 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
}
/**
- * The default state of Jumble, before connection to a server and after graceful/expected
- * disconnection from a server.
- */
- public static final int STATE_DISCONNECTED = 0;
- /**
- * A connection to the server is currently in progress.
- */
- public static final int STATE_CONNECTING = 1;
- /**
- * Jumble has received all data necessary for normal protocol communication with the server.
- */
- public static final int STATE_CONNECTED = 2;
- /**
- * The connection was lost due to either a kick/ban or socket I/O error.
- * Jumble can be reconnecting in this state.
- * @see IJumbleService#isReconnecting()
- * @see IJumbleService#cancelReconnect()
- */
- public static final int STATE_CONNECTION_LOST = 3;
-
- /**
* An action to immediately connect to a given Mumble server.
* Requires that {@link #EXTRAS_SERVER} is provided.
*/
@@ -146,10 +118,9 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
private PowerManager.WakeLock mWakeLock;
private Handler mHandler;
private JumbleCallbacks mCallbacks;
- private IJumbleService.Stub mBinder = new JumbleBinder();
private JumbleConnection mConnection;
- private int mConnectionState;
+ private ConnectionState mConnectionState;
private ModelHandler mModelHandler;
private AudioHandler mAudioHandler;
private BluetoothScoReceiver mBluetoothReceiver;
@@ -189,16 +160,12 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
mHandler.post(new Runnable() {
@Override
public void run() {
- if(!isConnected()) return;
+ if(!isConnectionEstablished()) return;
final User currentUser = mModelHandler.getUser(mConnection.getSession());
if(currentUser == null) return;
currentUser.setTalkState(state);
- try {
- mCallbacks.onUserTalkStateUpdated(currentUser);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onUserTalkStateUpdated(currentUser);
}
});
}
@@ -207,11 +174,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
private AudioOutput.AudioOutputListener mAudioOutputListener = new AudioOutput.AudioOutputListener() {
@Override
public void onUserTalkStateUpdated(final User user) {
- try {
- mCallbacks.onUserTalkStateUpdated(user);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onUserTalkStateUpdated(user);
}
@Override
@@ -234,7 +197,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
if (ACTION_CONNECT.equals(intent.getAction())) {
if (extras == null || !extras.containsKey(EXTRAS_SERVER)) {
- // Ensure that we have been provided all required attributes.
+ // Ensure that we have been provided all required attributes.```
throw new RuntimeException(ACTION_CONNECT + " requires a server provided in extras.");
}
connect();
@@ -256,7 +219,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
.setLogger(this)
.setEncodeListener(mAudioInputListener)
.setTalkingListener(mAudioOutputListener);
- mConnectionState = STATE_DISCONNECTED;
+ mConnectionState = ConnectionState.DISCONNECTED;
mBluetoothReceiver = new BluetoothScoReceiver(this, this);
registerReceiver(mBluetoothReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
}
@@ -264,22 +227,17 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
@Override
public void onDestroy() {
unregisterReceiver(mBluetoothReceiver);
- mCallbacks.kill();
super.onDestroy();
}
public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- public IJumbleService getBinder() {
- return mBinder;
+ return new JumbleBinder(this);
}
- public void connect() {
+ private void connect() {
try {
setReconnecting(false);
- mConnectionState = STATE_DISCONNECTED;
+ mConnectionState = ConnectionState.DISCONNECTED;
mConnection = new JumbleConnection(this);
mConnection.setForceTCP(mForceTcp);
@@ -291,22 +249,14 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
mLocalMuteHistory, mLocalIgnoreHistory);
mConnection.addTCPMessageHandlers(mModelHandler);
- mConnectionState = STATE_CONNECTING;
+ mConnectionState = ConnectionState.CONNECTING;
- try {
- mCallbacks.onConnecting();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onConnecting();
mConnection.connect(mServer.getHost(), mServer.getPort());
} catch (JumbleException e) {
e.printStackTrace();
- try {
- mCallbacks.onDisconnected(e);
- } catch (RemoteException e1) {
- e1.printStackTrace();
- }
+ mCallbacks.onDisconnected(e);
}
}
@@ -314,10 +264,18 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
mConnection.disconnect();
}
- public boolean isConnected() {
+ public boolean isConnectionEstablished() {
return mConnection != null && mConnection.isConnected();
}
+ /**
+ * @return true if Jumble has received the ServerSync message, indicating synchronization with
+ * the server's model and settings. This is the main state of the service.
+ */
+ public boolean isSynchronized() {
+ return mConnectionState == ConnectionState.CONNECTED;
+ }
+
@Override
public void onConnectionEstablished() {
// Send version information and authenticate.
@@ -342,7 +300,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
@Override
public void onConnectionSynchronized() {
- mConnectionState = STATE_CONNECTED;
+ mConnectionState = ConnectionState.CONNECTED;
Log.v(Constants.TAG, "Connected");
mWakeLock.acquire();
@@ -358,23 +316,12 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
onConnectionWarning(e.getMessage());
}
- try {
- mCallbacks.onConnected();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onConnected();
}
@Override
public void onConnectionHandshakeFailed(X509Certificate[] chain) {
- try {
- final ParcelableByteArray encodedCert = new ParcelableByteArray(chain[0].getEncoded());
- mCallbacks.onTLSHandshakeFailed(encodedCert);
- } catch (CertificateEncodingException e) {
- e.printStackTrace();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onTLSHandshakeFailed(chain);
}
@Override
@@ -382,13 +329,13 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
if (e != null) {
Log.e(Constants.TAG, "Error: " + e.getMessage() +
" (reason: " + e.getReason().name() + ")");
- mConnectionState = STATE_CONNECTION_LOST;
+ mConnectionState = ConnectionState.CONNECTION_LOST;
setReconnecting(mAutoReconnect
&& e.getReason() == JumbleException.JumbleDisconnectReason.CONNECTION_ERROR);
} else {
Log.v(Constants.TAG, "Disconnected");
- mConnectionState = STATE_DISCONNECTED;
+ mConnectionState = ConnectionState.DISCONNECTED;
}
if(mWakeLock.isHeld()) {
@@ -405,11 +352,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
// Halt SCO connection on shutdown.
mBluetoothReceiver.stopBluetoothSco();
- try {
- mCallbacks.onDisconnected(e);
- } catch (RemoteException re) {
- re.printStackTrace();
- }
+ mCallbacks.onDisconnected(e);
}
@Override
@@ -421,32 +364,23 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
public void logInfo(String message) {
if (mConnection == null || !mConnection.isSynchronized())
return; // don't log info prior to synchronization
- try {
- mCallbacks.onLogInfo(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onLogInfo(message);
}
@Override
public void logWarning(String message) {
- try {
- mCallbacks.onLogWarning(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onLogWarning(message);
}
@Override
public void logError(String message) {
- try {
- mCallbacks.onLogError(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mCallbacks.onLogError(message);
}
- private void setReconnecting(boolean reconnecting) {
+ public void setReconnecting(boolean reconnecting) {
+ if (mReconnecting == reconnecting)
+ return;
+
mReconnecting = reconnecting;
if (reconnecting) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
@@ -486,7 +420,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
* be known.
*/
private void createAudioHandler() throws AudioException {
- if (BuildConfig.DEBUG && mConnectionState != STATE_CONNECTED) {
+ if (BuildConfig.DEBUG && mConnectionState != ConnectionState.CONNECTED) {
throw new AssertionError("Attempted to instantiate audio handler when not connected!");
}
@@ -510,7 +444,7 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
* @return true if a reconnect is required for changes to take effect.
* @see com.morlunk.jumble.JumbleService
*/
- private boolean configureExtras(Bundle extras) throws AudioException {
+ public boolean configureExtras(Bundle extras) throws AudioException {
boolean reconnectNeeded = false;
if (extras.containsKey(EXTRAS_SERVER)) {
mServer = extras.getParcelable(EXTRAS_SERVER);
@@ -638,342 +572,97 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
}
}
- public class JumbleBinder extends IJumbleService.Stub {
- @Override
- public int getConnectionState() throws RemoteException {
- return mConnectionState;
- }
-
- @Override
- public JumbleException getConnectionError() throws RemoteException {
- return mConnection != null ? mConnection.getError() : null;
- }
-
- @Override
- public boolean isReconnecting() throws RemoteException {
- return mReconnecting;
- }
-
- @Override
- public void cancelReconnect() throws RemoteException {
- setReconnecting(false);
- }
-
- @Override
- public void disconnect() throws RemoteException {
- JumbleService.this.disconnect();
- }
-
- @Override
- public long getTCPLatency() throws RemoteException {
- return mConnection.getTCPLatency();
- }
-
- @Override
- public long getUDPLatency() throws RemoteException {
- return mConnection.getUDPLatency();
- }
-
- @Override
- public int getMaxBandwidth() throws RemoteException {
- return mConnection.getMaxBandwidth();
- }
-
- @Override
- public int getCurrentBandwidth() throws RemoteException {
- return mAudioHandler.getCurrentBandwidth();
- }
-
- @Override
- public int getServerVersion() throws RemoteException {
- return mConnection.getServerVersion();
- }
-
- @Override
- public String getServerRelease() throws RemoteException {
- return mConnection.getServerRelease();
- }
-
- @Override
- public String getServerOSName() throws RemoteException {
- return mConnection.getServerOSName();
- }
-
- @Override
- public String getServerOSVersion() throws RemoteException {
- return mConnection.getServerOSVersion();
- }
-
- @Override
- public int getSession() throws RemoteException {
- return mConnection != null ? mConnection.getSession() : -1;
- }
-
- @Override
- public IUser getSessionUser() throws RemoteException {
- return mModelHandler != null ? mModelHandler.getUser(getSession()) : null;
- }
-
- @Override
- public IChannel getSessionChannel() throws RemoteException {
- IUser user = getSessionUser();
- if (user != null) {
- return user.getChannel();
- }
- return null;
- }
-
- @Override
- public Server getConnectedServer() throws RemoteException {
- return mServer;
- }
-
- @Override
- public IUser getUser(int id) throws RemoteException {
- if (mModelHandler != null)
- return mModelHandler.getUser(id);
- return null;
- }
-
- @Override
- public IChannel getChannel(int id) throws RemoteException {
- if (mModelHandler != null)
- return mModelHandler.getChannel(id);
- return null;
- }
-
- @Override
- public IChannel getRootChannel() throws RemoteException {
- return getChannel(0);
- }
-
- @Override
- public int getPermissions() throws RemoteException {
- return mModelHandler != null ? mModelHandler.getPermissions() : 0;
- }
-
- @Override
- public int getTransmitMode() throws RemoteException {
- return mAudioHandler.getTransmitMode();
- }
-
- @Override
- public int getCodec() throws RemoteException {
- return mConnection.getCodec().ordinal(); // FIXME: ordinal is bad, make enum method
- }
-
- @Override
- public boolean usingBluetoothSco() throws RemoteException {
- return mBluetoothReceiver.isBluetoothScoOn();
- }
-
- @Override
- public void enableBluetoothSco() throws RemoteException {
- mBluetoothReceiver.startBluetoothSco();
- }
-
- @Override
- public void disableBluetoothSco() throws RemoteException {
- mBluetoothReceiver.stopBluetoothSco();
- }
-
- @Override
- public boolean isTalking() throws RemoteException {
- return mAudioHandler != null && mAudioHandler.isRecording();
- }
-
- @Override
- public void setTalkingState(boolean talking) throws RemoteException {
- if(getSessionUser() != null &&
- (getSessionUser().isSelfMuted() || getSessionUser().isMuted())) {
- return;
- }
-
- if (mAudioHandler.getTransmitMode() != Constants.TRANSMIT_PUSH_TO_TALK) {
- Log.w(Constants.TAG, "Attempted to set talking state when not using PTT");
- return;
- }
-
- try {
- mAudioHandler.setTalking(talking);
- } catch (AudioException e) {
- logError(e.getMessage());
- }
- }
-
- @Override
- public void joinChannel(int channel) throws RemoteException {
- moveUserToChannel(getSession(), channel);
- }
-
- @Override
- public void moveUserToChannel(int session, int channel) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSession(session);
- usb.setChannelId(channel);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
-
- @Override
- public void createChannel(int parent, String name, String description, int position, boolean temporary) throws RemoteException {
- Mumble.ChannelState.Builder csb = Mumble.ChannelState.newBuilder();
- csb.setParent(parent);
- csb.setName(name);
- csb.setDescription(description);
- csb.setPosition(position);
- csb.setTemporary(temporary);
- mConnection.sendTCPMessage(csb.build(), JumbleTCPMessageType.ChannelState);
- }
-
- @Override
- public void sendAccessTokens(List tokens) throws RemoteException {
- mConnection.sendAccessTokens(tokens);
- }
-
- @Override
- public void requestBanList() throws RemoteException {
- throw new UnsupportedOperationException("Not yet implemented"); // TODO
- }
-
- @Override
- public void requestUserList() throws RemoteException {
- throw new UnsupportedOperationException("Not yet implemented"); // TODO
- }
-
- @Override
- public void requestPermissions(int channel) throws RemoteException {
- Mumble.PermissionQuery.Builder pqb = Mumble.PermissionQuery.newBuilder();
- pqb.setChannelId(channel);
- mConnection.sendTCPMessage(pqb.build(), JumbleTCPMessageType.PermissionQuery);
- }
-
- @Override
- public void requestComment(int session) throws RemoteException {
- Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
- rbb.addSessionComment(session);
- mConnection.sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
- }
-
- @Override
- public void requestAvatar(int session) throws RemoteException {
- Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
- rbb.addSessionTexture(session);
- mConnection.sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
- }
-
- @Override
- public void requestChannelDescription(int channel) throws RemoteException {
- Mumble.RequestBlob.Builder rbb = Mumble.RequestBlob.newBuilder();
- rbb.addChannelDescription(channel);
- mConnection.sendTCPMessage(rbb.build(), JumbleTCPMessageType.RequestBlob);
- }
-
- @Override
- public void registerUser(int session) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSession(session);
- usb.setUserId(0);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
-
- @Override
- public void kickBanUser(int session, String reason, boolean ban) throws RemoteException {
- Mumble.UserRemove.Builder urb = Mumble.UserRemove.newBuilder();
- urb.setSession(session);
- urb.setReason(reason);
- urb.setBan(ban);
- mConnection.sendTCPMessage(urb.build(), JumbleTCPMessageType.UserRemove);
- }
-
- @Override
- public Message sendUserTextMessage(int session, String message) throws RemoteException {
- Mumble.TextMessage.Builder tmb = Mumble.TextMessage.newBuilder();
- tmb.addSession(session);
- tmb.setMessage(message);
- mConnection.sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage);
-
- User self = mModelHandler.getUser(getSession());
- User user = mModelHandler.getUser(session);
- List<User> users = new ArrayList<User>(1);
- users.add(user);
- return new Message(getSession(), self.getName(), new ArrayList<Channel>(0), new ArrayList<Channel>(0), users, message);
- }
-
- @Override
- public Message sendChannelTextMessage(int channel, String message, boolean tree) throws RemoteException {
- Mumble.TextMessage.Builder tmb = Mumble.TextMessage.newBuilder();
- if(tree) tmb.addTreeId(channel);
- else tmb.addChannelId(channel);
- tmb.setMessage(message);
- mConnection.sendTCPMessage(tmb.build(), JumbleTCPMessageType.TextMessage);
+ /**
+ * Exposes the current connection. The current connection is set once an attempt to connect to
+ * a server is made, and remains set until a subsequent connection. It remains available
+ * after disconnection to provide information regarding the terminated connection.
+ * @return The active {@link JumbleConnection}, or null if a connection has not been
+ * established yet.
+ */
+ public JumbleConnection getConnection() {
+ return mConnection;
+ }
- User self = mModelHandler.getUser(getSession());
- Channel targetChannel = mModelHandler.getChannel(channel);
- List<Channel> targetChannels = new ArrayList<Channel>();
- targetChannels.add(targetChannel);
- return new Message(getSession(), self.getName(), targetChannels, tree ? targetChannels : new ArrayList<Channel>(0), new ArrayList<User>(0), message);
- }
+ /**
+ * Returnes the current {@link AudioHandler}. An AudioHandler is instantiated upon connection
+ * to a server, and destroyed upon disconnection.
+ * @return the active AudioHandler, or null if there is no active connection.
+ */
+ public AudioHandler getAudioHandler() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
+ if (mAudioHandler == null && mConnectionState == ConnectionState.CONNECTED)
+ throw new RuntimeException("Audio handler should always be instantiated while connected!");
+ return mAudioHandler;
+ }
- @Override
- public void setUserComment(int session, String comment) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSession(session);
- usb.setComment(comment);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
+ /**
+ * Returns the current {@link ModelHandler}, containing the channel tree. A model handler is
+ * valid for the lifetime of a connection.
+ * @return the active ModelHandler, or null if there is no active connection.
+ */
+ public ModelHandler getModelHandler() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
+ if (mModelHandler == null && mConnectionState == ConnectionState.CONNECTED)
+ throw new RuntimeException("Model handler should always be instantiated while connected!");
+ return mModelHandler;
+ }
- @Override
- public void setPrioritySpeaker(int session, boolean priority) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSession(session);
- usb.setPrioritySpeaker(priority);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
+ /**
+ * Returns the bluetooth service provider, established after synchronization.
+ * @return The {@link BluetoothScoReceiver} attached to this service.
+ * @throws IllegalStateException if not synchronized or disconnected.
+ */
+ public BluetoothScoReceiver getBluetoothReceiver() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
+ return mBluetoothReceiver;
+ }
- @Override
- public void removeChannel(int channel) throws RemoteException {
- Mumble.ChannelRemove.Builder crb = Mumble.ChannelRemove.newBuilder();
- crb.setChannelId(channel);
- mConnection.sendTCPMessage(crb.build(), JumbleTCPMessageType.ChannelRemove);
- }
+ public boolean isReconnecting() {
+ return mReconnecting;
+ }
- @Override
- public void setMuteDeafState(int session, boolean mute, boolean deaf) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSession(session);
- usb.setMute(mute);
- usb.setDeaf(deaf);
- if (!mute) usb.setSuppress(false);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
+ public ConnectionState getConnectionState() {
+ return mConnectionState;
+ }
- @Override
- public void setSelfMuteDeafState(boolean mute, boolean deaf) throws RemoteException {
- Mumble.UserState.Builder usb = Mumble.UserState.newBuilder();
- usb.setSelfMute(mute);
- usb.setSelfDeaf(deaf);
- mConnection.sendTCPMessage(usb.build(), JumbleTCPMessageType.UserState);
- }
+ public Server getConnectedServer() {
+ return mServer;
+ }
- @Override
- public void registerObserver(IJumbleObserver observer) throws RemoteException {
- mCallbacks.registerObserver(observer);
- }
+ public void registerObserver(IJumbleObserver observer) {
+ mCallbacks.registerObserver(observer);
+ }
- @Override
- public void unregisterObserver(IJumbleObserver observer) throws RemoteException {
- mCallbacks.unregisterObserver(observer);
- }
+ public void unregisterObserver(IJumbleObserver observer) {
+ mCallbacks.unregisterObserver(observer);
+ }
- @Override
- public boolean reconfigure(Bundle extras) throws RemoteException {
- try {
- return configureExtras(extras);
- } catch (AudioException e) {
- e.printStackTrace();
- // TODO
- return true;
- }
- }
+ /**
+ * The current connection state of the service.
+ */
+ public enum ConnectionState {
+ /**
+ * The default state of Jumble, before connection to a server and after graceful/expected
+ * disconnection from a server.
+ */
+ DISCONNECTED,
+ /**
+ * A connection to the server is currently in progress.
+ */
+ CONNECTING,
+ /**
+ * Jumble has received all data necessary for normal protocol communication with the server.
+ */
+ CONNECTED,
+ /**
+ * The connection was lost due to either a kick/ban or socket I/O error.
+ * Jumble may be reconnecting in this state.
+ * @see JumbleBinder#isReconnecting()
+ * @see JumbleBinder#cancelReconnect()
+ */
+ CONNECTION_LOST
}
}
diff --git a/src/main/java/com/morlunk/jumble/model/Channel.java b/src/main/java/com/morlunk/jumble/model/Channel.java
index 7edc95f..142754f 100644
--- a/src/main/java/com/morlunk/jumble/model/Channel.java
+++ b/src/main/java/com/morlunk/jumble/model/Channel.java
@@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-public final class Channel extends IChannel.Stub implements Comparable<Channel> {
+public final class Channel implements IChannel, Comparable<Channel> {
private int mId;
private int mPosition;
private int mLevel;
@@ -68,10 +68,12 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
mUsers.remove(user);
}
+ @Override
public List<User> getUsers() {
return Collections.unmodifiableList(mUsers);
}
+ @Override
public int getId() {
return mId;
}
@@ -80,6 +82,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mId = mId;
}
+ @Override
public int getPosition() {
return mPosition;
}
@@ -88,6 +91,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mPosition = mPosition;
}
+ @Override
public boolean isTemporary() {
return mTemporary;
}
@@ -96,6 +100,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mTemporary = mTemporary;
}
+ @Override
public Channel getParent() {
return mParent;
}
@@ -104,6 +109,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mParent = mParent;
}
+ @Override
public String getName() {
return mName;
}
@@ -112,6 +118,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mName = mName;
}
+ @Override
public String getDescription() {
return mDescription;
}
@@ -120,6 +127,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mDescription = mDescription;
}
+ @Override
public byte[] getDescriptionHash() {
return mDescriptionHash;
}
@@ -128,6 +136,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
this.mDescriptionHash = mDescriptionHash;
}
+ @Override
public List<Channel> getSubchannels() {
return Collections.unmodifiableList(mSubchannels);
}
@@ -147,6 +156,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
mSubchannels.remove(channel);
}
+ @Override
public List<Channel> getLinks() {
return Collections.unmodifiableList(mLinks);
}
@@ -183,6 +193,7 @@ public final class Channel extends IChannel.Stub implements Comparable<Channel>
return userCount;
}
+ @Override
public int getPermissions() {
return mPermissions;
}
diff --git a/src/main/java/com/morlunk/jumble/model/IChannel.java b/src/main/java/com/morlunk/jumble/model/IChannel.java
new file mode 100644
index 0000000..e261ff3
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/model/IChannel.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.model;
+
+import java.util.List;
+
+public interface IChannel {
+ List<? extends IUser> getUsers();
+
+ int getId();
+
+ int getPosition();
+
+ boolean isTemporary();
+
+ IChannel getParent();
+
+ String getName();
+
+ String getDescription();
+
+ byte[] getDescriptionHash();
+
+ List<? extends IChannel> getSubchannels();
+
+ List<? extends IChannel> getLinks();
+
+ int getPermissions();
+}
diff --git a/src/main/java/com/morlunk/jumble/model/IMessage.java b/src/main/java/com/morlunk/jumble/model/IMessage.java
new file mode 100644
index 0000000..9a3ec2c
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/model/IMessage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.model;
+
+import java.util.List;
+
+public interface IMessage {
+ int getActor();
+
+ String getActorName();
+
+ List<Channel> getTargetChannels();
+
+ List<Channel> getTargetTrees();
+
+ List<User> getTargetUsers();
+
+ String getMessage();
+
+ long getReceivedTime();
+}
diff --git a/src/main/java/com/morlunk/jumble/model/IUser.java b/src/main/java/com/morlunk/jumble/model/IUser.java
new file mode 100644
index 0000000..b0311b7
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/model/IUser.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.model;
+
+/**
+ * Created by andrew on 15/10/15.
+ */
+public interface IUser {
+ int getSession();
+
+ Channel getChannel();
+
+ int getUserId();
+
+ String getName();
+
+ String getComment();
+
+ byte[] getCommentHash();
+
+ byte[] getTexture();
+
+ byte[] getTextureHash();
+
+ String getHash();
+
+ boolean isMuted();
+
+ boolean isDeafened();
+
+ boolean isSuppressed();
+
+ boolean isSelfMuted();
+
+ boolean isSelfDeafened();
+
+ boolean isPrioritySpeaker();
+
+ boolean isRecording();
+
+ boolean isLocalMuted();
+
+ boolean isLocalIgnored();
+
+ TalkState getTalkState();
+}
diff --git a/src/main/java/com/morlunk/jumble/model/Message.java b/src/main/java/com/morlunk/jumble/model/Message.java
index 17270da..202e803 100644
--- a/src/main/java/com/morlunk/jumble/model/Message.java
+++ b/src/main/java/com/morlunk/jumble/model/Message.java
@@ -32,7 +32,7 @@ import java.util.List;
* as the actor may no longer be on the server.
* Created by andrew on 03/12/13.
*/
-public class Message extends IMessage.Stub {
+public class Message implements IMessage {
private int mActor;
private String mActorName;
private List<Channel> mChannels;
@@ -58,30 +58,37 @@ public class Message extends IMessage.Stub {
mTrees = trees;
mUsers = users;
}
+ @Override
public int getActor() {
return mActor;
}
+ @Override
public String getActorName() {
return mActorName;
}
+ @Override
public List<Channel> getTargetChannels() {
return Collections.unmodifiableList(mChannels);
}
+ @Override
public List<Channel> getTargetTrees() {
return Collections.unmodifiableList(mTrees);
}
+ @Override
public List<User> getTargetUsers() {
return Collections.unmodifiableList(mUsers);
}
+ @Override
public String getMessage() {
return mMessage;
}
+ @Override
public long getReceivedTime() {
return mReceivedTime;
}
diff --git a/src/main/java/com/morlunk/jumble/model/User.java b/src/main/java/com/morlunk/jumble/model/User.java
index 559cbdf..3bfd31d 100644
--- a/src/main/java/com/morlunk/jumble/model/User.java
+++ b/src/main/java/com/morlunk/jumble/model/User.java
@@ -19,7 +19,7 @@ package com.morlunk.jumble.model;
import com.google.protobuf.ByteString;
-public class User extends IUser.Stub implements Comparable<User> {
+public class User implements IUser, Comparable<User> {
private int mSession;
private int mId = -1;
@@ -60,10 +60,12 @@ public class User extends IUser.Stub implements Comparable<User> {
mName = name;
}
+ @Override
public int getSession() {
return mSession;
}
+ @Override
public Channel getChannel() {
return mChannel;
}
@@ -82,6 +84,7 @@ public class User extends IUser.Stub implements Comparable<User> {
mChannel.addUser(this);
}
+ @Override
public int getUserId() {
return mId;
}
@@ -90,6 +93,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mId = mId;
}
+ @Override
public String getName() {
return mName;
}
@@ -98,6 +102,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mName = mName;
}
+ @Override
public String getComment() {
return mComment;
}
@@ -106,6 +111,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mComment = mComment;
}
+ @Override
public byte[] getCommentHash() {
return mCommentHash != null ? mCommentHash.toByteArray() : null;
}
@@ -114,6 +120,7 @@ public class User extends IUser.Stub implements Comparable<User> {
mCommentHash = commentHash;
}
+ @Override
public byte[] getTexture() {
return mTexture != null ? mTexture.toByteArray() : null;
}
@@ -122,6 +129,7 @@ public class User extends IUser.Stub implements Comparable<User> {
mTexture = texture;
}
+ @Override
public byte[] getTextureHash() {
return mTextureHash != null ? mTextureHash.toByteArray() : null;
}
@@ -130,6 +138,7 @@ public class User extends IUser.Stub implements Comparable<User> {
mTextureHash = textureHash;
}
+ @Override
public String getHash() {
return mHash;
}
@@ -138,6 +147,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mHash = mHash;
}
+ @Override
public boolean isMuted() {
return mMuted;
}
@@ -146,6 +156,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mMuted = mMuted;
}
+ @Override
public boolean isDeafened() {
return mDeafened;
}
@@ -154,6 +165,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mDeafened = mDeafened;
}
+ @Override
public boolean isSuppressed() {
return mSuppressed;
}
@@ -162,6 +174,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mSuppressed = mSuppressed;
}
+ @Override
public boolean isSelfMuted() {
return mSelfMuted;
}
@@ -170,6 +183,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mSelfMuted = mSelfMuted;
}
+ @Override
public boolean isSelfDeafened() {
return mSelfDeafened;
}
@@ -178,6 +192,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mSelfDeafened = mSelfDeafened;
}
+ @Override
public boolean isPrioritySpeaker() {
return mPrioritySpeaker;
}
@@ -186,6 +201,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mPrioritySpeaker = mPrioritySpeaker;
}
+ @Override
public boolean isRecording() {
return mRecording;
}
@@ -194,6 +210,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mRecording = mRecording;
}
+ @Override
public boolean isLocalMuted() {
return mLocalMuted;
}
@@ -202,6 +219,7 @@ public class User extends IUser.Stub implements Comparable<User> {
this.mLocalMuted = mLocalMuted;
}
+ @Override
public boolean isLocalIgnored() {
return mLocalIgnored;
}
@@ -210,6 +228,7 @@ public class User extends IUser.Stub implements Comparable<User> {
mLocalIgnored = localIgnored;
}
+ @Override
public TalkState getTalkState() {
return mTalkState;
}
diff --git a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
index 2bbbad9..6fd919f 100644
--- a/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
+++ b/src/main/java/com/morlunk/jumble/net/JumbleConnection.java
@@ -399,30 +399,44 @@ public class JumbleConnection implements JumbleTCP.TCPConnectionListener, Jumble
}
public int getServerVersion() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mServerVersion;
}
public String getServerRelease() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mServerRelease;
}
public String getServerOSName() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mServerOSName;
}
public String getServerOSVersion() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mServerOSVersion;
}
public long getTCPLatency() {
+ if (!isConnected())
+ throw new IllegalStateException("Not connected");
return mLastTCPPing;
}
public long getUDPLatency() {
+ if (!isConnected())
+ throw new IllegalStateException("Not connected");
return mLastUDPPing;
}
public int getSession() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mSession;
}
@@ -431,10 +445,14 @@ public class JumbleConnection implements JumbleTCP.TCPConnectionListener, Jumble
* @return the input bandwidth in bps, or -1 if not set.
*/
public int getMaxBandwidth() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mMaxBandwidth;
}
public JumbleUDPMessageType getCodec() {
+ if (!isSynchronized())
+ throw new IllegalStateException("Not synchronized");
return mCodec;
}
diff --git a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java
index 973fb3a..a14b803 100644
--- a/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java
+++ b/src/main/java/com/morlunk/jumble/protocol/ModelHandler.java
@@ -24,13 +24,13 @@ import android.os.RemoteException;
import android.util.Log;
import com.morlunk.jumble.Constants;
-import com.morlunk.jumble.IJumbleObserver;
import com.morlunk.jumble.R;
import com.morlunk.jumble.model.Channel;
import com.morlunk.jumble.model.Message;
import com.morlunk.jumble.model.User;
import com.morlunk.jumble.protobuf.Mumble;
import com.morlunk.jumble.protocol.JumbleTCPMessageListener;
+import com.morlunk.jumble.util.IJumbleObserver;
import com.morlunk.jumble.util.JumbleLogger;
import com.morlunk.jumble.util.MessageFormatter;
@@ -165,15 +165,10 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
channel.addLink(mChannels.get(link));
}
- final Channel finalChannel = channel;
- try {
- if(newChannel)
- mObserver.onChannelAdded(finalChannel);
- else
- mObserver.onChannelStateUpdated(finalChannel);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ if(newChannel)
+ mObserver.onChannelAdded(channel);
+ else
+ mObserver.onChannelStateUpdated(channel);
}
@Override
@@ -185,11 +180,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
if(parent != null) {
parent.removeSubchannel(channel);
}
- try {
- mObserver.onChannelRemoved(channel);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onChannelRemoved(channel);
}
}
@@ -204,11 +195,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
channel.setPermissions(msg.getPermissions());
if(msg.getChannelId() == 0) // If we're provided permissions for the root channel, we'll apply these as our server permissions.
mPermissions = channel.getPermissions();
- try {
- mObserver.onChannelPermissionsUpdated(channel);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onChannelPermissionsUpdated(channel);
}
}
@@ -343,11 +330,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
user.setChannel(channel);
if(!newUser) {
- try {
- mObserver.onUserJoinedChannel(finalUser, channel, old);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onUserJoinedChannel(finalUser, channel, old);
}
Channel sessionChannel = self != null ? self.getChannel() : null;
@@ -402,16 +385,10 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
if(msg.hasComment())
user.setComment(msg.getComment());
- final boolean finalNewUser = newUser;
-
- try {
- if(finalNewUser)
- mObserver.onUserConnected(finalUser);
- else
- mObserver.onUserStateUpdated(finalUser);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ if (newUser)
+ mObserver.onUserConnected(user);
+ else
+ mObserver.onUserStateUpdated(user);
}
@Override
@@ -428,12 +405,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
mLogger.logInfo(mContext.getString(R.string.chat_notify_disconnected, MessageFormatter.highlightString(user.getName())));
user.setChannel(null);
-
- try {
- mObserver.onUserRemoved(user, reason);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onUserRemoved(user, reason);
}
@Override
@@ -466,11 +438,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
else reason = mContext.getString(R.string.perm_denied);
}
- try {
- mObserver.onPermissionDenied(reason);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onPermissionDenied(reason);
}
@Override
@@ -490,11 +458,7 @@ public class ModelHandler extends JumbleTCPMessageListener.Stub {
String actorName = sender != null ? sender.getName() : mContext.getString(R.string.server);
Message message = new Message(msg.getActor(), actorName, channels, trees, users, msg.getMessage());
- try {
- mObserver.onMessageLogged(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ mObserver.onMessageLogged(message);
}
@Override
diff --git a/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java b/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java
new file mode 100644
index 0000000..d167da3
--- /dev/null
+++ b/src/main/java/com/morlunk/jumble/util/IJumbleObserver.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 Andrew Comminos <andrew@comminos.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.morlunk.jumble.util;
+
+import com.morlunk.jumble.model.IChannel;
+import com.morlunk.jumble.model.IMessage;
+import com.morlunk.jumble.model.IUser;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * Created by andrew on 18/10/15.
+ */
+public interface IJumbleObserver {
+ void onConnected();
+
+ void onConnecting();
+
+ void onDisconnected(JumbleException e);
+
+ void onTLSHandshakeFailed(X509Certificate[] chain);
+
+ void onChannelAdded(IChannel channel);
+
+ void onChannelStateUpdated(IChannel channel);
+
+ void onChannelRemoved(IChannel channel);
+
+ void onChannelPermissionsUpdated(IChannel channel);
+
+ void onUserConnected(IUser user);
+
+ void onUserStateUpdated(IUser user);
+
+ void onUserTalkStateUpdated(IUser user);
+
+ void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel);
+
+ void onUserRemoved(IUser user, String reason);
+
+ void onPermissionDenied(String reason);
+
+ void onMessageLogged(IMessage message);
+
+ void onLogInfo(String message);
+
+ void onLogWarning(String message);
+
+ void onLogError(String message);
+}
diff --git a/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java b/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
index 1f67a16..5fc1107 100644
--- a/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
+++ b/src/main/java/com/morlunk/jumble/util/JumbleCallbacks.java
@@ -17,214 +17,158 @@
package com.morlunk.jumble.util;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-
-import com.morlunk.jumble.IJumbleObserver;
import com.morlunk.jumble.model.IChannel;
import com.morlunk.jumble.model.IMessage;
import com.morlunk.jumble.model.IUser;
+import org.spongycastle.jcajce.provider.asymmetric.X509;
+
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* A composite wrapper around Jumble observers to easily broadcast to each observer.
* Created by andrew on 12/07/14.
*/
-public class JumbleCallbacks extends JumbleObserver.Stub {
- private final RemoteCallbackList<IJumbleObserver> mCallbacks;
+public class JumbleCallbacks implements IJumbleObserver {
+ private final Set<IJumbleObserver> mCallbacks;
public JumbleCallbacks() {
- mCallbacks = new RemoteCallbackList<IJumbleObserver>();
+ mCallbacks = new HashSet<>();
}
public void registerObserver(IJumbleObserver observer) {
- mCallbacks.register(observer);
+ mCallbacks.add(observer);
}
public void unregisterObserver(IJumbleObserver observer) {
- mCallbacks.unregister(observer);
- }
-
- public void kill() {
- mCallbacks.kill();
+ mCallbacks.remove(observer);
}
@Override
- public void onConnected() throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onConnected();
+ public void onConnected() {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onConnected();
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onConnecting() throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onConnecting();
+ public void onConnecting() {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onConnecting();
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onDisconnected(JumbleException e) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onDisconnected(e);
+ public void onDisconnected(JumbleException e) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onDisconnected(e);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onTLSHandshakeFailed(ParcelableByteArray cert) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onTLSHandshakeFailed(cert);
+ public void onTLSHandshakeFailed(X509Certificate[] chain) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onTLSHandshakeFailed(chain);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onChannelAdded(IChannel channel) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onChannelAdded(channel);
+ public void onChannelAdded(IChannel channel) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onChannelAdded(channel);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onChannelStateUpdated(IChannel channel) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onChannelStateUpdated(channel);
+ public void onChannelStateUpdated(IChannel channel) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onChannelStateUpdated(channel);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onChannelRemoved(IChannel channel) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onChannelRemoved(channel);
+ public void onChannelRemoved(IChannel channel) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onChannelRemoved(channel);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onChannelPermissionsUpdated(IChannel channel) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onChannelPermissionsUpdated(channel);
+ public void onChannelPermissionsUpdated(IChannel channel) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onChannelPermissionsUpdated(channel);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onUserConnected(IUser user) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onUserConnected(user);
+ public void onUserConnected(IUser user) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onUserConnected(user);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onUserStateUpdated(IUser user) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onUserStateUpdated(user);
+ public void onUserStateUpdated(IUser user) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onUserStateUpdated(user);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onUserTalkStateUpdated(IUser user) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onUserTalkStateUpdated(user);
+ public void onUserTalkStateUpdated(IUser user) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onUserTalkStateUpdated(user);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onUserJoinedChannel(user, newChannel, oldChannel);
+ public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onUserJoinedChannel(user, newChannel, oldChannel);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onUserRemoved(IUser user, String reason) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onUserRemoved(user, reason);
+ public void onUserRemoved(IUser user, String reason) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onUserRemoved(user, reason);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onPermissionDenied(String reason) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onPermissionDenied(reason);
+ public void onPermissionDenied(String reason) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onPermissionDenied(reason);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onMessageLogged(IMessage message) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onMessageLogged(message);
+ public void onMessageLogged(IMessage message) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onMessageLogged(message);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onLogInfo(String message) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onLogInfo(message);
+ public void onLogInfo(String message) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onLogInfo(message);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onLogWarning(String message) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onLogWarning(message);
+ public void onLogWarning(String message) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onLogWarning(message);
}
- mCallbacks.finishBroadcast();
}
@Override
- public void onLogError(String message) throws RemoteException {
- int i = mCallbacks.beginBroadcast();
- while(i > 0) {
- i--;
- mCallbacks.getBroadcastItem(i).onLogError(message);
+ public void onLogError(String message) {
+ for (IJumbleObserver observer : mCallbacks) {
+ observer.onLogError(message);
}
- mCallbacks.finishBroadcast();
}
}
diff --git a/src/main/java/com/morlunk/jumble/util/JumbleObserver.java b/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
index 3c51383..91f2751 100644
--- a/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
+++ b/src/main/java/com/morlunk/jumble/util/JumbleObserver.java
@@ -17,109 +17,104 @@
package com.morlunk.jumble.util;
-import android.os.RemoteException;
-
-import com.morlunk.jumble.IJumbleObserver;
-import com.morlunk.jumble.model.Channel;
import com.morlunk.jumble.model.IChannel;
import com.morlunk.jumble.model.IMessage;
import com.morlunk.jumble.model.IUser;
-import com.morlunk.jumble.model.Message;
-import com.morlunk.jumble.model.User;
+
+import java.security.cert.X509Certificate;
/**
* Stub class for Jumble service observation.
* Created by andrew on 31/07/13.
*/
-public class JumbleObserver extends IJumbleObserver.Stub {
+public class JumbleObserver implements IJumbleObserver {
@Override
- public void onConnected() throws RemoteException {
+ public void onConnected() {
}
@Override
- public void onConnecting() throws RemoteException {
+ public void onConnecting() {
}
@Override
- public void onDisconnected(JumbleException e) throws RemoteException {
+ public void onDisconnected(JumbleException e) {
}
@Override
- public void onTLSHandshakeFailed(ParcelableByteArray cert) throws RemoteException {
+ public void onTLSHandshakeFailed(X509Certificate[] chain) {
}
@Override
- public void onChannelAdded(IChannel channel) throws RemoteException {
+ public void onChannelAdded(IChannel channel) {
}
@Override
- public void onChannelStateUpdated(IChannel channel) throws RemoteException {
+ public void onChannelStateUpdated(IChannel channel) {
}
@Override
- public void onChannelRemoved(IChannel channel) throws RemoteException {
+ public void onChannelRemoved(IChannel channel) {
}
@Override
- public void onChannelPermissionsUpdated(IChannel channel) throws RemoteException {
+ public void onChannelPermissionsUpdated(IChannel channel) {
}
@Override
- public void onUserConnected(IUser user) throws RemoteException {
+ public void onUserConnected(IUser user) {
}
@Override
- public void onUserStateUpdated(IUser user) throws RemoteException {
+ public void onUserStateUpdated(IUser user) {
}
@Override
- public void onUserTalkStateUpdated(IUser user) throws RemoteException {
-
+ public void onUserTalkStateUpdated(IUser user) {
+
}
@Override
- public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) throws RemoteException {
+ public void onUserJoinedChannel(IUser user, IChannel newChannel, IChannel oldChannel) {
}
@Override
- public void onUserRemoved(IUser user, String reason) throws RemoteException {
+ public void onUserRemoved(IUser user, String reason) {
}
@Override
- public void onPermissionDenied(String reason) throws RemoteException {
+ public void onPermissionDenied(String reason) {
}
@Override
- public void onMessageLogged(IMessage message) throws RemoteException {
+ public void onMessageLogged(IMessage message) {
}
@Override
- public void onLogInfo(String message) throws RemoteException {
+ public void onLogInfo(String message) {
}
@Override
- public void onLogWarning(String message) throws RemoteException {
+ public void onLogWarning(String message) {
}
@Override
- public void onLogError(String message) throws RemoteException {
+ public void onLogError(String message) {
}
-
}
diff --git a/src/main/java/com/morlunk/jumble/util/ParcelableByteArray.java b/src/main/java/com/morlunk/jumble/util/ParcelableByteArray.java
deleted file mode 100644
index 801cb0a..0000000
--- a/src/main/java/com/morlunk/jumble/util/ParcelableByteArray.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 Andrew Comminos
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.morlunk.jumble.util;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Created by andrew on 05/04/14.
- */
-public class ParcelableByteArray implements Parcelable {
-
- private byte[] mByteArray;
-
- public ParcelableByteArray(byte[] array) {
- mByteArray = array;
- }
-
- private ParcelableByteArray(Parcel in) {
- int length = in.readInt();
- mByteArray = new byte[length];
- in.readByteArray(mByteArray);
- }
-
- public byte[] getBytes() {
- return mByteArray;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mByteArray.length);
- dest.writeByteArray(mByteArray);
- }
-
- public static final Creator<ParcelableByteArray> CREATOR = new Creator<ParcelableByteArray>() {
-
- @Override
- public ParcelableByteArray createFromParcel(Parcel source) {
- return new ParcelableByteArray(source);
- }
-
- @Override
- public ParcelableByteArray[] newArray(int size) {
- return new ParcelableByteArray[size];
- }
- };
-}