mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Massive refactoring to use pseudonyms instead of nicknames for contacts.
The invitation and private messaging UIs are currently broken. Some key rotation bugs were fixed; others may have been created (unit tests needed). An encoding for private keys was added. Pseudonyms were moved out of the messaging package and ratings were moved in.
This commit is contained in:
@@ -19,8 +19,8 @@ import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalBorder;
|
||||
import net.sf.briar.api.Contact;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.event.ContactAddedEvent;
|
||||
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||
@@ -52,7 +52,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
@@ -87,36 +87,6 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
|
||||
// Bind to the service so we can wait for the DB to be opened
|
||||
bindService(new Intent(BriarService.class.getName()),
|
||||
serviceConnection, 0);
|
||||
|
||||
// Add some fake contacts to the database in a background thread
|
||||
insertFakeContacts();
|
||||
}
|
||||
|
||||
// FIXME: Remove this
|
||||
private void insertFakeContacts() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to be bound and started
|
||||
serviceConnection.waitForStartup();
|
||||
// If there are no contacts in the DB, create some fake ones
|
||||
Collection<Contact> contacts = db.getContacts();
|
||||
if(contacts.isEmpty()) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Inserting fake contacts");
|
||||
db.addContact("Alice");
|
||||
db.addContact("Bob");
|
||||
}
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,7 +96,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
|
||||
}
|
||||
|
||||
private void loadContacts() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to be bound and started
|
||||
|
||||
@@ -19,7 +19,7 @@ class ContactListItem {
|
||||
}
|
||||
|
||||
String getContactName() {
|
||||
return contact.getName();
|
||||
return contact.getAuthor().getName();
|
||||
}
|
||||
|
||||
long getLastConnected() {
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.sf.briar.android.BriarService;
|
||||
import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalBorder;
|
||||
import net.sf.briar.api.Author;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
@@ -28,7 +29,6 @@ import net.sf.briar.api.db.event.GroupMessageAddedEvent;
|
||||
import net.sf.briar.api.db.event.MessageExpiredEvent;
|
||||
import net.sf.briar.api.db.event.RatingChangedEvent;
|
||||
import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
|
||||
import net.sf.briar.api.messaging.Author;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
@@ -6,17 +6,17 @@ import static android.view.View.INVISIBLE;
|
||||
import static android.widget.LinearLayout.HORIZONTAL;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.text.DateFormat.SHORT;
|
||||
import static net.sf.briar.api.Rating.GOOD;
|
||||
import static net.sf.briar.api.Rating.UNRATED;
|
||||
import static net.sf.briar.api.messaging.Rating.GOOD;
|
||||
import static net.sf.briar.api.messaging.Rating.UNRATED;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.sf.briar.R;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.Author;
|
||||
import net.sf.briar.api.db.GroupMessageHeader;
|
||||
import net.sf.briar.api.messaging.Author;
|
||||
import net.sf.briar.api.messaging.Rating;
|
||||
import net.sf.briar.util.StringUtils;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
@@ -6,15 +6,8 @@ import static android.widget.LinearLayout.HORIZONTAL;
|
||||
import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static net.sf.briar.api.Rating.BAD;
|
||||
import static net.sf.briar.api.Rating.GOOD;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
@@ -29,11 +22,8 @@ import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalBorder;
|
||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.GroupMessageHeader;
|
||||
import net.sf.briar.api.db.NoSuchSubscriptionException;
|
||||
@@ -42,13 +32,8 @@ import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.GroupMessageAddedEvent;
|
||||
import net.sf.briar.api.db.event.MessageExpiredEvent;
|
||||
import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
|
||||
import net.sf.briar.api.messaging.Author;
|
||||
import net.sf.briar.api.messaging.AuthorFactory;
|
||||
import net.sf.briar.api.messaging.Group;
|
||||
import net.sf.briar.api.messaging.GroupFactory;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageFactory;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
@@ -73,13 +58,8 @@ implements OnClickListener, DatabaseListener {
|
||||
private ImageButton newGroupButton = null, composeButton = null;
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile CryptoComponent crypto;
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
@Inject private volatile AuthorFactory authorFactory;
|
||||
@Inject private volatile GroupFactory groupFactory;
|
||||
@Inject private volatile MessageFactory messageFactory;
|
||||
private volatile boolean restricted = false;
|
||||
|
||||
@Override
|
||||
@@ -134,154 +114,6 @@ implements OnClickListener, DatabaseListener {
|
||||
// Bind to the service so we can wait for the DB to be opened
|
||||
bindService(new Intent(BriarService.class.getName()),
|
||||
serviceConnection, 0);
|
||||
|
||||
// Add some fake messages to the database in a background thread
|
||||
insertFakeMessages();
|
||||
}
|
||||
|
||||
// FIXME: Remove this
|
||||
private void insertFakeMessages() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to be bound and started
|
||||
serviceConnection.waitForStartup();
|
||||
// If there are no groups in the DB, create some fake ones
|
||||
Collection<Group> groups = db.getSubscriptions();
|
||||
if(!groups.isEmpty()) return;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Inserting fake groups and messages");
|
||||
// We'll also need a contact to receive messages from
|
||||
ContactId contactId = db.addContact("Dave");
|
||||
// Finally, we'll need some authors for the messages
|
||||
long now = System.currentTimeMillis();
|
||||
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Key generation took " + duration + " ms");
|
||||
byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||
PrivateKey privateKey = keyPair.getPrivate();
|
||||
Author author = authorFactory.createAuthor("Batman",
|
||||
publicKey);
|
||||
db.setRating(author.getId(), BAD);
|
||||
Author author1 = authorFactory.createAuthor("Duckman",
|
||||
publicKey);
|
||||
db.setRating(author1.getId(), GOOD);
|
||||
// Insert some fake groups and make them visible
|
||||
Group group = groupFactory.createGroup("DisneyLeaks");
|
||||
db.subscribe(group);
|
||||
db.setVisibility(group.getId(), Arrays.asList(contactId));
|
||||
Group group1 = groupFactory.createGroup("Godwin's Lore");
|
||||
db.subscribe(group1);
|
||||
db.setVisibility(group1.getId(), Arrays.asList(contactId));
|
||||
Group group2 = groupFactory.createGroup(
|
||||
"All Kids Love Blog", publicKey);
|
||||
db.subscribe(group2);
|
||||
db.setVisibility(group2.getId(), Arrays.asList(contactId));
|
||||
// Insert some text messages to the unrestricted groups
|
||||
for(int i = 0; i < 20; i++) {
|
||||
String body;
|
||||
if(i % 3 == 0) {
|
||||
body = "Message " + i + " is short.";
|
||||
} else {
|
||||
body = "Message " + i + " is long enough to wrap"
|
||||
+ " onto a second line on some screens.";
|
||||
}
|
||||
Group g = i % 2 == 0 ? group : group1;
|
||||
Message m;
|
||||
now = System.currentTimeMillis();
|
||||
if(i % 5 == 0) {
|
||||
m = messageFactory.createAnonymousMessage(null, g,
|
||||
"text/plain", body.getBytes("UTF-8"));
|
||||
} else if(i % 5 == 2) {
|
||||
m = messageFactory.createPseudonymousMessage(null,
|
||||
g, author, privateKey, "text/plain",
|
||||
body.getBytes("UTF-8"));
|
||||
} else {
|
||||
m = messageFactory.createPseudonymousMessage(null,
|
||||
g, author1, privateKey, "text/plain",
|
||||
body.getBytes("UTF-8"));
|
||||
}
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO)) {
|
||||
LOG.info("Message creation took " +
|
||||
duration + " ms");
|
||||
}
|
||||
now = System.currentTimeMillis();
|
||||
if(Math.random() < 0.5) db.addLocalGroupMessage(m);
|
||||
else db.receiveMessage(contactId, m);
|
||||
db.setReadFlag(m.getId(), i % 4 == 0);
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO)) {
|
||||
LOG.info("Message storage took " +
|
||||
duration + " ms");
|
||||
}
|
||||
}
|
||||
// Insert a non-text message
|
||||
Message m = messageFactory.createAnonymousMessage(null,
|
||||
group, "image/jpeg", new byte[1000]);
|
||||
db.receiveMessage(contactId, m);
|
||||
// Insert a long text message
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(int i = 0; i < 100; i++)
|
||||
s.append("This is a very tedious message. ");
|
||||
String body = s.toString();
|
||||
m = messageFactory.createAnonymousMessage(m.getId(),
|
||||
group1, "text/plain", body.getBytes("UTF-8"));
|
||||
db.addLocalGroupMessage(m);
|
||||
// Insert some text messages to the restricted group
|
||||
for(int i = 0; i < 20; i++) {
|
||||
if(i % 3 == 0) {
|
||||
body = "Message " + i + " is short.";
|
||||
} else {
|
||||
body = "Message " + i + " is long enough to wrap"
|
||||
+ " onto a second line on some screens.";
|
||||
}
|
||||
now = System.currentTimeMillis();
|
||||
if(i % 5 == 0) {
|
||||
m = messageFactory.createAnonymousMessage(null,
|
||||
group2, privateKey, "text/plain",
|
||||
body.getBytes("UTF-8"));
|
||||
} else if(i % 5 == 2) {
|
||||
m = messageFactory.createPseudonymousMessage(null,
|
||||
group2, privateKey, author, privateKey,
|
||||
"text/plain", body.getBytes("UTF-8"));
|
||||
} else {
|
||||
m = messageFactory.createPseudonymousMessage(null,
|
||||
group2, privateKey, author1, privateKey,
|
||||
"text/plain", body.getBytes("UTF-8"));
|
||||
}
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO)) {
|
||||
LOG.info("Message creation took " +
|
||||
duration + " ms");
|
||||
}
|
||||
now = System.currentTimeMillis();
|
||||
if(Math.random() < 0.5) db.addLocalGroupMessage(m);
|
||||
else db.receiveMessage(contactId, m);
|
||||
db.setReadFlag(m.getId(), i % 4 == 0);
|
||||
duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO)) {
|
||||
LOG.info("Message storage took " +
|
||||
duration + " ms");
|
||||
}
|
||||
}
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,8 +4,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.briar.android.DescendingHeaderComparator;
|
||||
import net.sf.briar.api.Author;
|
||||
import net.sf.briar.api.db.GroupMessageHeader;
|
||||
import net.sf.briar.api.messaging.Author;
|
||||
import net.sf.briar.api.messaging.Group;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.text.DateFormat.SHORT;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static net.sf.briar.api.Rating.BAD;
|
||||
import static net.sf.briar.api.Rating.GOOD;
|
||||
import static net.sf.briar.api.Rating.UNRATED;
|
||||
import static net.sf.briar.api.messaging.Rating.BAD;
|
||||
import static net.sf.briar.api.messaging.Rating.GOOD;
|
||||
import static net.sf.briar.api.messaging.Rating.UNRATED;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -24,15 +24,15 @@ import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalBorder;
|
||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.AuthorId;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchMessageException;
|
||||
import net.sf.briar.api.messaging.AuthorId;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
import net.sf.briar.api.messaging.Rating;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
|
||||
@@ -4,7 +4,6 @@ import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.sf.briar.api.crypto.Password;
|
||||
import net.sf.briar.api.db.DatabaseConfig;
|
||||
import net.sf.briar.api.ui.UiCallback;
|
||||
import android.app.Application;
|
||||
@@ -39,13 +38,8 @@ public class HelloWorldModule extends AbstractModule {
|
||||
return app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public Password getPassword() {
|
||||
return new Password() {
|
||||
|
||||
public char[] getPassword() {
|
||||
return "foo bar".toCharArray();
|
||||
}
|
||||
};
|
||||
public char[] getPassword() {
|
||||
return "foo bar".toCharArray();
|
||||
}
|
||||
|
||||
public long getMaxSize() {
|
||||
|
||||
@@ -1,25 +1,14 @@
|
||||
package net.sf.briar.android.invitation;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.android.BriarActivity;
|
||||
import net.sf.briar.android.BriarService;
|
||||
import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.api.AuthorId;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.android.ReferenceManager;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.invitation.InvitationListener;
|
||||
import net.sf.briar.api.invitation.InvitationState;
|
||||
import net.sf.briar.api.invitation.InvitationTask;
|
||||
import net.sf.briar.api.invitation.InvitationTaskFactory;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@@ -27,12 +16,6 @@ import com.google.inject.Inject;
|
||||
public class AddContactActivity extends BriarActivity
|
||||
implements InvitationListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AddContactActivity.class.getName());
|
||||
|
||||
private final BriarServiceConnection serviceConnection =
|
||||
new BriarServiceConnection();
|
||||
|
||||
@Inject private BundleEncrypter bundleEncrypter;
|
||||
@Inject private CryptoComponent crypto;
|
||||
@Inject private InvitationTaskFactory invitationTaskFactory;
|
||||
@@ -40,6 +23,7 @@ implements InvitationListener {
|
||||
private AddContactView view = null;
|
||||
private InvitationTask task = null;
|
||||
private long taskHandle = -1;
|
||||
private AuthorId localAuthorId = null;
|
||||
private String networkName = null;
|
||||
private boolean useBluetooth = false;
|
||||
private int localInvitationCode = -1, remoteInvitationCode = -1;
|
||||
@@ -47,10 +31,7 @@ implements InvitationListener {
|
||||
private boolean connectionFailed = false;
|
||||
private boolean localCompared = false, remoteCompared = false;
|
||||
private boolean localMatched = false, remoteMatched = false;
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
private String contactName = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
@@ -60,6 +41,8 @@ implements InvitationListener {
|
||||
setView(new NetworkSetupView(this));
|
||||
} else {
|
||||
// Restore the activity's state
|
||||
byte[] id = state.getByteArray("net.sf.briar.LOCAL_AUTHOR_ID");
|
||||
if(id != null) localAuthorId = new AuthorId(id);
|
||||
networkName = state.getString("net.sf.briar.NETWORK_NAME");
|
||||
useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
|
||||
taskHandle = state.getLong("net.sf.briar.TASK_HANDLE", -1);
|
||||
@@ -70,7 +53,8 @@ implements InvitationListener {
|
||||
localInvitationCode = state.getInt("net.sf.briar.LOCAL_CODE");
|
||||
remoteInvitationCode = state.getInt("net.sf.briar.REMOTE_CODE");
|
||||
connectionFailed = state.getBoolean("net.sf.briar.FAILED");
|
||||
if(state.getBoolean("net.sf.briar.MATCHED")) {
|
||||
contactName = state.getString("net.sf.briar.CONTACT_NAME");
|
||||
if(contactName != null) {
|
||||
localCompared = remoteCompared = true;
|
||||
localMatched = remoteMatched = true;
|
||||
}
|
||||
@@ -81,10 +65,10 @@ implements InvitationListener {
|
||||
setView(new InvitationCodeView(this));
|
||||
} else if(connectionFailed) {
|
||||
setView(new ConnectionFailedView(this));
|
||||
} else if(localMatched && remoteMatched) {
|
||||
setView(new ContactAddedView(this));
|
||||
} else {
|
||||
} else if(contactName == null) {
|
||||
setView(new CodesDoNotMatchView(this));
|
||||
} else {
|
||||
setView(new ContactAddedView(this));
|
||||
}
|
||||
} else {
|
||||
// A background task exists - listen to it and get its state
|
||||
@@ -98,6 +82,7 @@ implements InvitationListener {
|
||||
remoteCompared = s.getRemoteCompared();
|
||||
localMatched = s.getLocalMatched();
|
||||
remoteMatched = s.getRemoteMatched();
|
||||
contactName = s.getContactName();
|
||||
// Set the appropriate view for the state
|
||||
if(localInvitationCode == -1) {
|
||||
setView(new NetworkSetupView(this));
|
||||
@@ -112,15 +97,14 @@ implements InvitationListener {
|
||||
} else if(!remoteCompared) {
|
||||
setView(new WaitForContactView(this));
|
||||
} else if(localMatched && remoteMatched) {
|
||||
setView(new ContactAddedView(this));
|
||||
if(contactName == null)
|
||||
setView(new WaitForContactView(this));
|
||||
else setView(new ContactAddedView(this));
|
||||
} else {
|
||||
setView(new CodesDoNotMatchView(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bind to the service so we can wait for the DB to be opened
|
||||
bindService(new Intent(BriarService.class.getName()),
|
||||
serviceConnection, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,12 +115,16 @@ implements InvitationListener {
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle state) {
|
||||
if(localAuthorId != null) {
|
||||
state.putByteArray("net.sf.briar.LOCAL_AUTHOR_ID",
|
||||
localAuthorId.getBytes());
|
||||
}
|
||||
state.putString("net.sf.briar.NETWORK_NAME", networkName);
|
||||
state.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
|
||||
state.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
|
||||
state.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
|
||||
state.putBoolean("net.sf.briar.FAILED", connectionFailed);
|
||||
state.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
|
||||
state.putString("net.sf.briar.CONTACT_NAME", contactName);
|
||||
if(task != null) state.putLong("net.sf.briar.TASK_HANDLE", taskHandle);
|
||||
bundleEncrypter.encrypt(state);
|
||||
}
|
||||
@@ -145,7 +133,6 @@ implements InvitationListener {
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if(task != null) task.removeListener(this);
|
||||
unbindService(serviceConnection);
|
||||
}
|
||||
|
||||
void setView(AddContactView view) {
|
||||
@@ -157,6 +144,7 @@ implements InvitationListener {
|
||||
void reset(AddContactView view) {
|
||||
task = null;
|
||||
taskHandle = -1;
|
||||
localAuthorId = null;
|
||||
networkName = null;
|
||||
useBluetooth = false;
|
||||
localInvitationCode = -1;
|
||||
@@ -164,9 +152,14 @@ implements InvitationListener {
|
||||
connectionFailed = false;
|
||||
localCompared = remoteCompared = false;
|
||||
localMatched = remoteMatched = false;
|
||||
contactName = null;
|
||||
setView(view);
|
||||
}
|
||||
|
||||
void setLocalAuthorId(AuthorId localAuthorId) {
|
||||
this.localAuthorId = localAuthorId;
|
||||
}
|
||||
|
||||
void setNetworkName(String networkName) {
|
||||
this.networkName = networkName;
|
||||
}
|
||||
@@ -191,8 +184,10 @@ implements InvitationListener {
|
||||
|
||||
void remoteInvitationCodeEntered(int code) {
|
||||
setView(new ConnectionView(this));
|
||||
// FIXME: These calls are blocking the UI thread for too long
|
||||
task = invitationTaskFactory.createTask(localInvitationCode, code);
|
||||
if(localAuthorId == null) throw new IllegalStateException();
|
||||
if(localInvitationCode == -1) throw new IllegalStateException();
|
||||
task = invitationTaskFactory.createTask(localAuthorId,
|
||||
localInvitationCode, code);
|
||||
taskHandle = referenceManager.putReference(task, InvitationTask.class);
|
||||
task.addListener(AddContactActivity.this);
|
||||
task.addListener(new ReferenceCleaner(referenceManager, taskHandle));
|
||||
@@ -204,11 +199,10 @@ implements InvitationListener {
|
||||
}
|
||||
|
||||
void remoteConfirmationCodeEntered(int code) {
|
||||
localCompared = true;
|
||||
if(code == remoteConfirmationCode) {
|
||||
localMatched = true;
|
||||
if(remoteMatched) setView(new ContactAddedView(this));
|
||||
else if(remoteCompared) setView(new CodesDoNotMatchView(this));
|
||||
else setView(new WaitForContactView(this));
|
||||
setView(new WaitForContactView(this));
|
||||
task.localConfirmationSucceeded();
|
||||
} else {
|
||||
setView(new CodesDoNotMatchView(this));
|
||||
@@ -216,23 +210,8 @@ implements InvitationListener {
|
||||
}
|
||||
}
|
||||
|
||||
void addContactAndFinish(final String nickname) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
db.addContact(nickname);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
finish();
|
||||
String getContactName() {
|
||||
return contactName;
|
||||
}
|
||||
|
||||
public void connectionSucceeded(final int localCode, final int remoteCode) {
|
||||
@@ -259,8 +238,6 @@ implements InvitationListener {
|
||||
public void run() {
|
||||
remoteCompared = true;
|
||||
remoteMatched = true;
|
||||
if(localMatched)
|
||||
setView(new ContactAddedView(AddContactActivity.this));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -275,6 +252,23 @@ implements InvitationListener {
|
||||
});
|
||||
}
|
||||
|
||||
public void pseudonymExchangeSucceeded(final String remoteName) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
contactName = remoteName;
|
||||
setView(new ContactAddedView(AddContactActivity.this));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void pseudonymExchangeFailed() {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
setView(new ConnectionFailedView(AddContactActivity.this));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the reference to the invitation task when the task completes.
|
||||
* This class is static to prevent memory leaks.
|
||||
@@ -299,11 +293,19 @@ implements InvitationListener {
|
||||
}
|
||||
|
||||
public void remoteConfirmationSucceeded() {
|
||||
referenceManager.removeReference(handle, InvitationTask.class);
|
||||
// Wait for the pseudonym exchange to succeed or fail
|
||||
}
|
||||
|
||||
public void remoteConfirmationFailed() {
|
||||
referenceManager.removeReference(handle, InvitationTask.class);
|
||||
}
|
||||
|
||||
public void pseudonymExchangeSucceeded(String remoteName) {
|
||||
referenceManager.removeReference(handle, InvitationTask.class);
|
||||
}
|
||||
|
||||
public void pseudonymExchangeFailed() {
|
||||
referenceManager.removeReference(handle, InvitationTask.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
package net.sf.briar.android.invitation;
|
||||
|
||||
import static android.text.InputType.TYPE_CLASS_TEXT;
|
||||
import static android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS;
|
||||
import static android.text.InputType.TYPE_TEXT_VARIATION_PERSON_NAME;
|
||||
import static android.view.Gravity.CENTER;
|
||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||
import net.sf.briar.R;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import android.content.Context;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
public class ContactAddedView extends AddContactView implements OnClickListener,
|
||||
OnEditorActionListener {
|
||||
|
||||
EditText nicknameEntry = null;
|
||||
public class ContactAddedView extends AddContactView
|
||||
implements OnClickListener {
|
||||
|
||||
ContactAddedView(Context ctx) {
|
||||
super(ctx);
|
||||
@@ -46,50 +37,21 @@ OnEditorActionListener {
|
||||
innerLayout.addView(added);
|
||||
addView(innerLayout);
|
||||
|
||||
TextView enterNickname = new TextView(ctx);
|
||||
enterNickname.setGravity(CENTER_HORIZONTAL);
|
||||
enterNickname.setPadding(10, 0, 10, 10);
|
||||
enterNickname.setText(R.string.enter_nickname);
|
||||
addView(enterNickname);
|
||||
TextView contactName = new TextView(ctx);
|
||||
contactName.setTextSize(22);
|
||||
contactName.setPadding(10, 0, 10, 10);
|
||||
contactName.setText(container.getContactName());
|
||||
addView(contactName);
|
||||
|
||||
innerLayout = new LinearLayout(ctx);
|
||||
innerLayout.setOrientation(HORIZONTAL);
|
||||
innerLayout.setGravity(CENTER);
|
||||
|
||||
final Button doneButton = new Button(ctx);
|
||||
Button doneButton = new Button(ctx);
|
||||
doneButton.setLayoutParams(CommonLayoutParams.WRAP_WRAP);
|
||||
doneButton.setText(R.string.done_button);
|
||||
doneButton.setEnabled(false);
|
||||
doneButton.setOnClickListener(this);
|
||||
|
||||
nicknameEntry = new EditText(ctx) {
|
||||
@Override
|
||||
protected void onTextChanged(CharSequence text, int start,
|
||||
int lengthBefore, int lengthAfter) {
|
||||
doneButton.setEnabled(text.length() > 0);
|
||||
}
|
||||
};
|
||||
nicknameEntry.setTextSize(26);
|
||||
nicknameEntry.setPadding(10, 0, 10, 10);
|
||||
nicknameEntry.setMinEms(5);
|
||||
nicknameEntry.setMaxEms(20);
|
||||
nicknameEntry.setMaxLines(1);
|
||||
nicknameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS |
|
||||
TYPE_TEXT_VARIATION_PERSON_NAME);
|
||||
nicknameEntry.setOnEditorActionListener(this);
|
||||
innerLayout.addView(nicknameEntry);
|
||||
innerLayout.addView(doneButton);
|
||||
addView(innerLayout);
|
||||
}
|
||||
|
||||
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
||||
String nickname = textView.getText().toString();
|
||||
if(nickname.length() > 0) container.addContactAndFinish(nickname);
|
||||
return true;
|
||||
addView(doneButton);
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
String nickname = nicknameEntry.getText().toString();
|
||||
container.addContactAndFinish(nickname);
|
||||
container.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,13 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
|
||||
void populate() {
|
||||
removeAllViews();
|
||||
Context ctx = getContext();
|
||||
TextView sameNetwork = new TextView(ctx);
|
||||
sameNetwork.setTextSize(14);
|
||||
sameNetwork.setPadding(10, 10, 10, 10);
|
||||
sameNetwork.setText(R.string.same_network);
|
||||
addView(sameNetwork);
|
||||
TextView chooseIdentity = new TextView(ctx);
|
||||
chooseIdentity.setTextSize(14);
|
||||
chooseIdentity.setPadding(10, 10, 10, 10);
|
||||
chooseIdentity.setText(R.string.choose_identity);
|
||||
addView(chooseIdentity);
|
||||
|
||||
// FIXME: Add a spinner for choosing which identity to use
|
||||
|
||||
WifiWidget wifi = new WifiWidget(ctx);
|
||||
wifi.init(this);
|
||||
|
||||
@@ -10,7 +10,7 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.SpinnerAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
class ContactNameSpinnerAdapter extends ArrayAdapter<Contact>
|
||||
public class ContactNameSpinnerAdapter extends ArrayAdapter<Contact>
|
||||
implements SpinnerAdapter {
|
||||
|
||||
ContactNameSpinnerAdapter(Context context) {
|
||||
@@ -24,7 +24,7 @@ implements SpinnerAdapter {
|
||||
name.setTextSize(18);
|
||||
name.setMaxLines(1);
|
||||
name.setPadding(10, 10, 10, 10);
|
||||
name.setText(getItem(position).getName());
|
||||
name.setText(getItem(position).getAuthor().getName());
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import static android.widget.LinearLayout.VERTICAL;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@@ -25,7 +23,6 @@ import net.sf.briar.api.Contact;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.db.PrivateMessageHeader;
|
||||
@@ -34,8 +31,6 @@ import net.sf.briar.api.db.event.DatabaseEvent;
|
||||
import net.sf.briar.api.db.event.DatabaseListener;
|
||||
import net.sf.briar.api.db.event.MessageExpiredEvent;
|
||||
import net.sf.briar.api.db.event.PrivateMessageAddedEvent;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageFactory;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
@@ -60,9 +55,7 @@ implements OnClickListener, DatabaseListener {
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
@Inject private volatile MessageFactory messageFactory;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
@@ -93,70 +86,6 @@ implements OnClickListener, DatabaseListener {
|
||||
// Bind to the service so we can wait for the DB to be opened
|
||||
bindService(new Intent(BriarService.class.getName()),
|
||||
serviceConnection, 0);
|
||||
|
||||
// Add some fake messages to the database in a background thread
|
||||
insertFakeMessages();
|
||||
}
|
||||
|
||||
// FIXME: Remove this
|
||||
private void insertFakeMessages() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to be bound and started
|
||||
serviceConnection.waitForStartup();
|
||||
// If there are no messages in the DB, create some fake ones
|
||||
Collection<PrivateMessageHeader> headers =
|
||||
db.getPrivateMessageHeaders();
|
||||
if(!headers.isEmpty()) return;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Inserting fake private messages");
|
||||
// We'll also need a contact to exchange messages with
|
||||
ContactId contactId = db.addContact("Carol");
|
||||
// Insert some text messages to and from the contact
|
||||
for(int i = 0; i < 20; i++) {
|
||||
String body;
|
||||
if(i % 3 == 0) {
|
||||
body = "Message " + i + " is short.";
|
||||
} else {
|
||||
body = "Message " + i + " is long enough to"
|
||||
+ " wrap onto a second line on some"
|
||||
+ " screens.";
|
||||
}
|
||||
Message m = messageFactory.createPrivateMessage(null,
|
||||
"text/plain", body.getBytes("UTF-8"));
|
||||
if(Math.random() < 0.5)
|
||||
db.addLocalPrivateMessage(m, contactId);
|
||||
else db.receiveMessage(contactId, m);
|
||||
db.setReadFlag(m.getId(), i % 4 == 0);
|
||||
}
|
||||
// Insert a non-text message
|
||||
Message m = messageFactory.createPrivateMessage(null,
|
||||
"image/jpeg", new byte[1000]);
|
||||
db.receiveMessage(contactId, m);
|
||||
// Insert a long text message
|
||||
StringBuilder s = new StringBuilder();
|
||||
for(int i = 0; i < 100; i++)
|
||||
s.append("This is a very tedious message. ");
|
||||
m = messageFactory.createPrivateMessage(m.getId(),
|
||||
"text/plain", s.toString().getBytes("UTF-8"));
|
||||
db.addLocalPrivateMessage(m, contactId);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(GeneralSecurityException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,7 +31,7 @@ class ConversationListItem {
|
||||
}
|
||||
|
||||
String getContactName() {
|
||||
return contact.getName();
|
||||
return contact.getAuthor().getName();
|
||||
}
|
||||
|
||||
String getSubject() {
|
||||
|
||||
Reference in New Issue
Block a user