diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java index 204df03fe08ab8609d8c279fcaeeeed0f3d7596f..1cbd13eb256c3571caa019a51bd08e7221207364 100644 --- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java +++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java @@ -57,7 +57,7 @@ implements InvitationListener { private BluetoothWifiStateReceiver receiver = null; private int localInvitationCode = -1, remoteInvitationCode = -1; private int localConfirmationCode = -1, remoteConfirmationCode = -1; - private boolean connectionFailed = false; + private boolean connected = false, connectionFailed = false; private boolean localCompared = false, remoteCompared = false; private boolean localMatched = false, remoteMatched = false; private String contactName = null; @@ -109,6 +109,7 @@ implements InvitationListener { remoteInvitationCode = s.getRemoteInvitationCode(); localConfirmationCode = s.getLocalConfirmationCode(); remoteConfirmationCode = s.getRemoteConfirmationCode(); + connected = s.getConnected(); connectionFailed = s.getConnectionFailed(); localCompared = s.getLocalCompared(); remoteCompared = s.getRemoteCompared(); @@ -120,10 +121,12 @@ implements InvitationListener { setView(new NetworkSetupView(this)); } else if(remoteInvitationCode == -1) { setView(new InvitationCodeView(this)); - } else if(localConfirmationCode == -1) { - setView(new ConnectionView(this)); } else if(connectionFailed) { setView(new ConnectionFailedView(this)); + } else if(connected && localConfirmationCode == -1) { + setView(new ConnectedView(this)); + } else if(localConfirmationCode == -1) { + setView(new ConnectionView(this)); } else if(!localCompared) { setView(new ConfirmationCodeView(this)); } else if(!remoteCompared) { @@ -296,7 +299,26 @@ implements InvitationListener { return contactName; } - public void connectionSucceeded(final int localCode, final int remoteCode) { + public void connectionSucceeded() { + runOnUiThread(new Runnable() { + public void run() { + connected = true; + setView(new ConnectedView(AddContactActivity.this)); + } + }); + } + + public void connectionFailed() { + runOnUiThread(new Runnable() { + public void run() { + connectionFailed = true; + setView(new ConnectionFailedView(AddContactActivity.this)); + } + }); + } + + public void keyAgreementSucceeded(final int localCode, + final int remoteCode) { runOnUiThread(new Runnable() { public void run() { localConfirmationCode = localCode; @@ -306,7 +328,7 @@ implements InvitationListener { }); } - public void connectionFailed() { + public void keyAgreementFailed() { runOnUiThread(new Runnable() { public void run() { connectionFailed = true; @@ -390,14 +412,22 @@ implements InvitationListener { this.handle = handle; } - public void connectionSucceeded(int localCode, int remoteCode) { - // Wait for remote confirmation to succeed or fail + public void connectionSucceeded() { + // Wait for key agreement to succeed or fail } public void connectionFailed() { referenceManager.removeReference(handle, InvitationTask.class); } + public void keyAgreementSucceeded(int localCode, int remoteCode) { + // Wait for remote confirmation to succeed or fail + } + + public void keyAgreementFailed() { + referenceManager.removeReference(handle, InvitationTask.class); + } + public void remoteConfirmationSucceeded() { // Wait for the pseudonym exchange to succeed or fail } diff --git a/briar-android/src/net/sf/briar/android/invitation/ConnectedView.java b/briar-android/src/net/sf/briar/android/invitation/ConnectedView.java new file mode 100644 index 0000000000000000000000000000000000000000..ba73343fb10f61a5ae044f072ce58e5e5909695b --- /dev/null +++ b/briar-android/src/net/sf/briar/android/invitation/ConnectedView.java @@ -0,0 +1,34 @@ +package net.sf.briar.android.invitation; + +import static android.view.Gravity.CENTER; +import net.sf.briar.R; +import android.content.Context; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class ConnectedView extends AddContactView { + + ConnectedView(Context ctx) { + super(ctx); + } + + void populate() { + removeAllViews(); + Context ctx = getContext(); + LinearLayout innerLayout = new LinearLayout(ctx); + innerLayout.setOrientation(HORIZONTAL); + innerLayout.setGravity(CENTER); + + ImageView icon = new ImageView(ctx); + icon.setImageResource(R.drawable.navigation_accept); + innerLayout.addView(icon); + + TextView connected = new TextView(ctx); + connected.setTextSize(22); + connected.setPadding(10, 10, 10, 10); + connected.setText(R.string.connected_to_contact); + innerLayout.addView(connected); + addView(innerLayout); + } +} diff --git a/briar-api/src/net/sf/briar/api/invitation/InvitationListener.java b/briar-api/src/net/sf/briar/api/invitation/InvitationListener.java index b7c3ccd2fc62e2ca7ef306e16f19b1a830c103bf..29726eacfd5737bc758e15f329f4923c53db0420 100644 --- a/briar-api/src/net/sf/briar/api/invitation/InvitationListener.java +++ b/briar-api/src/net/sf/briar/api/invitation/InvitationListener.java @@ -6,38 +6,42 @@ package net.sf.briar.api.invitation; */ public interface InvitationListener { - /** Called if a connection is established and key agreement succeeds. */ - void connectionSucceeded(int localCode, int remoteCode); + /** Called if a connection to the remote peer is established. */ + void connectionSucceeded(); /** - * Called if a connection cannot be established. This indicates that the - * protocol has ended unsuccessfully. + * Called if a connection to the remote peer cannot be established. This + * indicates that the protocol has ended unsuccessfully. */ void connectionFailed(); + /** Called if key agreement with the remote peer succeeds. */ + void keyAgreementSucceeded(int localCode, int remoteCode); + /** - * Informs the local peer that the remote peer's confirmation check - * succeeded. + * Called if key agreement with the remote peer fails or the connection is + * lost. This indicates that the protocol has ended unsuccessfully. */ + void keyAgreementFailed(); + + /** Called if the remote peer's confirmation check succeeds. */ void remoteConfirmationSucceeded(); /** - * Informs the local peer that the remote peer's confirmation check did - * not succeed, or the connection was lost during confirmation. This - * indicates that the protocol has ended unsuccessfully. + * Called if remote peer's confirmation check fails or the connection is + * lost. This indicates that the protocol has ended unsuccessfully. */ void remoteConfirmationFailed(); /** - * Informs the local peer of the name used by the remote peer. Called if - * the exchange of pseudonyms succeeds. This indicates that the protocol - * has ended successfully. + * Called if the exchange of pseudonyms succeeds. This indicates that the + * protocol has ended successfully. */ void pseudonymExchangeSucceeded(String remoteName); /** - * Called if the exchange of pseudonyms fails. This indicates that the - * protocol has ended unsuccessfully. + * Called if the exchange of pseudonyms fails or the connection is lost. + * This indicates that the protocol has ended unsuccessfully. */ void pseudonymExchangeFailed(); } diff --git a/briar-api/src/net/sf/briar/api/invitation/InvitationState.java b/briar-api/src/net/sf/briar/api/invitation/InvitationState.java index 0a65863d38d680a551a2173b539cd2aaac9790df..0e03efe80235b8215e2dcac8cace743d2b9ae2f0 100644 --- a/briar-api/src/net/sf/briar/api/invitation/InvitationState.java +++ b/briar-api/src/net/sf/briar/api/invitation/InvitationState.java @@ -4,20 +4,21 @@ public class InvitationState { private final int localInvitationCode, remoteInvitationCode; private final int localConfirmationCode, remoteConfirmationCode; - private final boolean connectionFailed; + private final boolean connected, connectionFailed; private final boolean localCompared, remoteCompared; private final boolean localMatched, remoteMatched; private final String contactName; public InvitationState(int localInvitationCode, int remoteInvitationCode, int localConfirmationCode, int remoteConfirmationCode, - boolean connectionFailed, boolean localCompared, + boolean connected, boolean connectionFailed, boolean localCompared, boolean remoteCompared, boolean localMatched, boolean remoteMatched, String contactName) { this.localInvitationCode = localInvitationCode; this.remoteInvitationCode = remoteInvitationCode; this.localConfirmationCode = localConfirmationCode; this.remoteConfirmationCode = remoteConfirmationCode; + this.connected = connected; this.connectionFailed = connectionFailed; this.localCompared = localCompared; this.remoteCompared = remoteCompared; @@ -42,6 +43,10 @@ public class InvitationState { return remoteConfirmationCode; } + public boolean getConnected() { + return connected; + } + public boolean getConnectionFailed() { return connectionFailed; } diff --git a/briar-core/src/net/sf/briar/invitation/AliceConnector.java b/briar-core/src/net/sf/briar/invitation/AliceConnector.java index ad49087a1d0c1a0374ee2ba3da920b80dce0b090..580195cd1c070109050c6604d6d62fb6368f3a66 100644 --- a/briar-core/src/net/sf/briar/invitation/AliceConnector.java +++ b/briar-core/src/net/sf/briar/invitation/AliceConnector.java @@ -91,10 +91,12 @@ class AliceConnector extends Connector { secret = deriveMasterSecret(hash, key, true); } catch(IOException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + group.keyAgreementFailed(); tryToClose(conn, true); return; } catch(GeneralSecurityException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + group.keyAgreementFailed(); tryToClose(conn, true); return; } @@ -102,7 +104,7 @@ class AliceConnector extends Connector { if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded"); int[] codes = crypto.deriveConfirmationCodes(secret); int aliceCode = codes[0], bobCode = codes[1]; - group.connectionSucceeded(aliceCode, bobCode); + group.keyAgreementSucceeded(aliceCode, bobCode); // Exchange confirmation results try { sendConfirmation(w); diff --git a/briar-core/src/net/sf/briar/invitation/BobConnector.java b/briar-core/src/net/sf/briar/invitation/BobConnector.java index a86b1ea01359756f3a289f795a3f620cd9f3dd46..8d7d2ad09f58f23e4a69aec280d8dc622a27082b 100644 --- a/briar-core/src/net/sf/briar/invitation/BobConnector.java +++ b/briar-core/src/net/sf/briar/invitation/BobConnector.java @@ -91,10 +91,12 @@ class BobConnector extends Connector { secret = deriveMasterSecret(hash, key, false); } catch(IOException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + group.keyAgreementFailed(); tryToClose(conn, true); return; } catch(GeneralSecurityException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + group.keyAgreementFailed(); tryToClose(conn, true); return; } @@ -102,7 +104,7 @@ class BobConnector extends Connector { if(LOG.isLoggable(INFO)) LOG.info(pluginName + " agreement succeeded"); int[] codes = crypto.deriveConfirmationCodes(secret); int aliceCode = codes[0], bobCode = codes[1]; - group.connectionSucceeded(bobCode, aliceCode); + group.keyAgreementSucceeded(bobCode, aliceCode); // Exchange confirmation results try { if(receiveConfirmation(r)) group.remoteConfirmationSucceeded(); diff --git a/briar-core/src/net/sf/briar/invitation/ConnectorGroup.java b/briar-core/src/net/sf/briar/invitation/ConnectorGroup.java index a96b1b556e94adab2fd6c16cb44a25f8f5b5dc6d..47f0beb6053c9dd1f7b9b3509cae760ca40449f9 100644 --- a/briar-core/src/net/sf/briar/invitation/ConnectorGroup.java +++ b/briar-core/src/net/sf/briar/invitation/ConnectorGroup.java @@ -101,7 +101,7 @@ class ConnectorGroup extends Thread implements InvitationTask { public synchronized InvitationState addListener(InvitationListener l) { listeners.add(l); return new InvitationState(localInvitationCode, remoteInvitationCode, - localConfirmationCode, remoteConfirmationCode, + localConfirmationCode, remoteConfirmationCode, connected.get(), connectionFailed, localCompared, remoteCompared, localMatched, remoteMatched, remoteName); } @@ -202,16 +202,24 @@ class ConnectorGroup extends Thread implements InvitationTask { } boolean getAndSetConnected() { - return connected.getAndSet(true); + boolean redundant = connected.getAndSet(true); + if(!redundant) { + for(InvitationListener l : listeners) l.connectionSucceeded(); + } + return redundant; } - void connectionSucceeded(int localCode, int remoteCode) { + void keyAgreementSucceeded(int localCode, int remoteCode) { synchronized(this) { localConfirmationCode = localCode; remoteConfirmationCode = remoteCode; } for(InvitationListener l : listeners) - l.connectionSucceeded(localCode, remoteCode); + l.keyAgreementSucceeded(localCode, remoteCode); + } + + void keyAgreementFailed() { + for(InvitationListener l : listeners) l.keyAgreementFailed(); } void remoteConfirmationSucceeded() {