Provide earlier feedback in the UI when connecting to a new contact.

Partially addresses issue #3611924.
This commit is contained in:
akwizgran
2013-05-15 18:22:04 +01:00
parent 07ab659c6b
commit 635973c845
7 changed files with 114 additions and 29 deletions

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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() {