diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 550e381e7..b43e6620e 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -13,15 +13,15 @@
Connected
Last connected <br /> %1$s
Add a Contact
- Choose an identity to use with this contact:
- Wi-Fi is not available on this device
+ Your identity:
+ Wi-Fi is NOT AVAILABLE
Wi-Fi is OFF
Wi-Fi is DISCONNECTED
- Wi-Fi is CONNECTED to %1$s
- Bluetooth is not available on this device
+ Wi-Fi is connected to %1$s
+ Bluetooth is NOT AVAILABLE
Bluetooth is OFF
Bluetooth is NOT DISCOVERABLE
- Bluetooth is DISCOVERABLE
+ Bluetooth is discoverable
Continue
Your invitation code is
Please enter your contact\'s invitation code:
@@ -43,7 +43,8 @@
From: %1$s
To: %1$s
New Message
- To:
+ From:
+ To:
(Anonymous)
Groups
New Post
diff --git a/briar-android/src/net/sf/briar/android/AuthorNameComparator.java b/briar-android/src/net/sf/briar/android/AuthorNameComparator.java
new file mode 100644
index 000000000..acde1829d
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/AuthorNameComparator.java
@@ -0,0 +1,16 @@
+package net.sf.briar.android;
+
+import java.util.Comparator;
+
+import net.sf.briar.api.Author;
+
+public class AuthorNameComparator implements Comparator {
+
+ public static final AuthorNameComparator INSTANCE =
+ new AuthorNameComparator();
+
+ public int compare(Author a1, Author a2) {
+ return String.CASE_INSENSITIVE_ORDER.compare(a1.getName(),
+ a2.getName());
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/LocalAuthorNameSpinnerAdapter.java b/briar-android/src/net/sf/briar/android/LocalAuthorNameSpinnerAdapter.java
new file mode 100644
index 000000000..ffeb3feb9
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/LocalAuthorNameSpinnerAdapter.java
@@ -0,0 +1,36 @@
+package net.sf.briar.android;
+
+import java.util.ArrayList;
+
+import net.sf.briar.api.LocalAuthor;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+public class LocalAuthorNameSpinnerAdapter extends ArrayAdapter
+implements SpinnerAdapter {
+
+ public LocalAuthorNameSpinnerAdapter(Context context) {
+ super(context, android.R.layout.simple_spinner_item,
+ new ArrayList());
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView name = new TextView(getContext());
+ name.setTextSize(18);
+ name.setMaxLines(1);
+ name.setPadding(10, 10, 10, 10);
+ name.setText(getItem(position).getName());
+ return name;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView,
+ ViewGroup parent) {
+ return getView(position, convertView, parent);
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
index 294f18da9..32bbb5a9c 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
@@ -6,7 +6,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -122,10 +121,8 @@ OnClickListener, OnItemClickListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms");
- // Wait for the headers to be displayed in the UI
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, headers);
- latch.await();
+ // Display the headers in the UI
+ displayHeaders(headers);
} catch(NoSuchSubscriptionException e) {
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
finishOnUiThread();
@@ -134,25 +131,20 @@ OnClickListener, OnItemClickListener {
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
- private void displayHeaders(final CountDownLatch latch,
- final Collection headers) {
+ private void displayHeaders(final Collection headers) {
runOnUiThread(new Runnable() {
public void run() {
- try {
- adapter.clear();
- for(GroupMessageHeader h : headers) adapter.add(h);
- adapter.sort(AscendingHeaderComparator.INSTANCE);
- selectFirstUnread();
- } finally {
- latch.countDown();
- }
+ adapter.clear();
+ for(GroupMessageHeader h : headers) adapter.add(h);
+ adapter.sort(AscendingHeaderComparator.INSTANCE);
+ selectFirstUnread();
}
});
}
@@ -203,7 +195,7 @@ OnClickListener, OnItemClickListener {
}
} else if(e instanceof MessageExpiredEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
- loadHeaders(); // FIXME: Don't reload everything
+ loadHeaders();
} else if(e instanceof RatingChangedEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
loadHeaders();
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
index f173274fa..baa57973b 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -11,7 +11,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -130,8 +129,6 @@ implements OnClickListener, DatabaseListener {
// Wait for the service to be bound and started
serviceConnection.waitForStartup();
// Load the subscribed groups from the DB
- Collection latches =
- new ArrayList();
long now = System.currentTimeMillis();
for(Group g : db.getSubscriptions()) {
// Filter out restricted/unrestricted groups
@@ -141,9 +138,7 @@ implements OnClickListener, DatabaseListener {
Collection headers =
db.getMessageHeaders(g.getId());
// Display the headers in the UI
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, g, headers);
- latches.add(latch);
+ displayHeaders(g, headers);
} catch(NoSuchSubscriptionException e) {
if(LOG.isLoggable(INFO))
LOG.info("Subscription removed");
@@ -152,39 +147,33 @@ implements OnClickListener, DatabaseListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Full load took " + duration + " ms");
- // Wait for the headers to be displayed in the UI
- for(CountDownLatch latch : latches) latch.await();
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
- private void displayHeaders(final CountDownLatch latch, final Group g,
+ private void displayHeaders(final Group g,
final Collection headers) {
runOnUiThread(new Runnable() {
public void run() {
- try {
- // Remove the old item, if any
- GroupListItem item = findGroup(g.getId());
- if(item != null) adapter.remove(item);
- // Add a new item if there are any headers to display
- if(!headers.isEmpty()) {
- List headerList =
- new ArrayList(headers);
- adapter.add(new GroupListItem(g, headerList));
- adapter.sort(GroupComparator.INSTANCE);
- }
- selectFirstUnread();
- } finally {
- latch.countDown();
+ // Remove the old item, if any
+ GroupListItem item = findGroup(g.getId());
+ if(item != null) adapter.remove(item);
+ // Add a new item if there are any headers to display
+ if(!headers.isEmpty()) {
+ List headerList =
+ new ArrayList(headers);
+ adapter.add(new GroupListItem(g, headerList));
+ adapter.sort(GroupComparator.INSTANCE);
}
+ selectFirstUnread();
}
});
}
@@ -241,7 +230,7 @@ implements OnClickListener, DatabaseListener {
}
} else if(e instanceof MessageExpiredEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
- loadHeaders(); // FIXME: Don't reload everything
+ loadHeaders();
} else if(e instanceof SubscriptionRemovedEvent) {
// Reload the group, expecting NoSuchSubscriptionException
Group g = ((SubscriptionRemovedEvent) e).getGroup();
@@ -263,9 +252,7 @@ implements OnClickListener, DatabaseListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Partial load took " + duration + " ms");
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, g, headers);
- latch.await();
+ displayHeaders(g, headers);
} catch(NoSuchSubscriptionException e) {
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
removeGroup(g.getId());
@@ -274,7 +261,7 @@ implements OnClickListener, DatabaseListener {
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
diff --git a/briar-android/src/net/sf/briar/android/groups/ReadGroupMessageActivity.java b/briar-android/src/net/sf/briar/android/groups/ReadGroupMessageActivity.java
index b8b33637f..48b925723 100644
--- a/briar-android/src/net/sf/briar/android/groups/ReadGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/ReadGroupMessageActivity.java
@@ -26,8 +26,8 @@ import net.sf.briar.android.widgets.HorizontalBorder;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.android.BundleEncrypter;
+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.NoSuchMessageException;
import net.sf.briar.api.messaging.GroupId;
@@ -72,7 +72,7 @@ implements OnClickListener {
// 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;
private volatile MessageId messageId = null;
private volatile AuthorId authorId = null;
@@ -234,7 +234,7 @@ implements OnClickListener {
}
private void setReadInDatabase(final boolean read) {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
@@ -263,7 +263,7 @@ implements OnClickListener {
}
private void loadMessageBody() {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
@@ -329,7 +329,7 @@ implements OnClickListener {
}
private void setRatingInDatabase(final Rating r) {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
index 1668c92ed..1b1be08a0 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
@@ -17,14 +17,17 @@ import java.util.concurrent.Executor;
import java.util.logging.Logger;
import net.sf.briar.R;
+import net.sf.briar.android.AuthorNameComparator;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.android.LocalAuthorNameSpinnerAdapter;
import net.sf.briar.android.widgets.CommonLayoutParams;
import net.sf.briar.android.widgets.HorizontalSpace;
+import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
+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.messaging.Group;
import net.sf.briar.api.messaging.GroupId;
@@ -47,7 +50,7 @@ import android.widget.TextView;
import com.google.inject.Inject;
public class WriteGroupMessageActivity extends BriarActivity
-implements OnClickListener, OnItemSelectedListener {
+implements OnItemSelectedListener, OnClickListener {
private static final Logger LOG =
Logger.getLogger(WriteGroupMessageActivity.class.getName());
@@ -56,16 +59,18 @@ implements OnClickListener, OnItemSelectedListener {
new BriarServiceConnection();
@Inject private BundleEncrypter bundleEncrypter;
- private GroupNameSpinnerAdapter adapter = null;
- private Spinner spinner = null;
+ private LocalAuthorNameSpinnerAdapter fromAdapter = null;
+ private GroupNameSpinnerAdapter toAdapter = null;
+ private Spinner fromSpinner = null, toSpinner = null;
private ImageButton sendButton = null;
private EditText content = null;
// 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;
private volatile boolean restricted = false;
+ private volatile LocalAuthor localAuthor = null;
private volatile Group group = null;
private volatile GroupId groupId = null;
private volatile MessageId parentId = null;
@@ -85,33 +90,51 @@ implements OnClickListener, OnItemSelectedListener {
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setOrientation(VERTICAL);
- LinearLayout actionBar = new LinearLayout(this);
- actionBar.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
- actionBar.setOrientation(HORIZONTAL);
- actionBar.setGravity(CENTER_VERTICAL);
+ LinearLayout header = new LinearLayout(this);
+ header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+ header.setOrientation(HORIZONTAL);
+ header.setGravity(CENTER_VERTICAL);
+
+ TextView from = new TextView(this);
+ from.setTextSize(18);
+ from.setPadding(10, 10, 10, 10);
+ from.setText(R.string.from);
+ header.addView(from);
+
+ fromAdapter = new LocalAuthorNameSpinnerAdapter(this);
+ fromSpinner = new Spinner(this);
+ fromSpinner.setOnItemSelectedListener(this);
+ loadLocalAuthorList();
+ header.addView(fromSpinner);
+
+ header.addView(new HorizontalSpace(this));
+
+ sendButton = new ImageButton(this);
+ sendButton.setBackgroundResource(0);
+ sendButton.setImageResource(R.drawable.social_send_now);
+ sendButton.setEnabled(false); // Enabled when a group is selected
+ sendButton.setOnClickListener(this);
+ header.addView(sendButton);
+ layout.addView(header);
+
+ header = new LinearLayout(this);
+ header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+ header.setOrientation(HORIZONTAL);
+ header.setGravity(CENTER_VERTICAL);
TextView to = new TextView(this);
to.setTextSize(18);
to.setPadding(10, 10, 10, 10);
to.setText(R.string.to);
- actionBar.addView(to);
+ header.addView(to);
- adapter = new GroupNameSpinnerAdapter(this);
- spinner = new Spinner(this);
- spinner.setAdapter(adapter);
- spinner.setOnItemSelectedListener(this);
+ toAdapter = new GroupNameSpinnerAdapter(this);
+ toSpinner = new Spinner(this);
+ toSpinner.setAdapter(toAdapter);
+ toSpinner.setOnItemSelectedListener(this);
loadGroupList();
- actionBar.addView(spinner);
-
- actionBar.addView(new HorizontalSpace(this));
-
- sendButton = new ImageButton(this);
- sendButton.setBackgroundResource(0);
- sendButton.setImageResource(R.drawable.social_send_now);
- sendButton.setEnabled(false);
- sendButton.setOnClickListener(this);
- actionBar.addView(sendButton);
- layout.addView(actionBar);
+ header.addView(toSpinner);
+ layout.addView(header);
content = new EditText(this);
content.setPadding(10, 10, 10, 10);
@@ -128,20 +151,48 @@ implements OnClickListener, OnItemSelectedListener {
serviceConnection, 0);
}
- // FIXME: If restricted, only load groups the user can post to
- private void loadGroupList() {
- dbExecutor.execute(new Runnable() {
+ private void loadLocalAuthorList() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
- List postable = new ArrayList();
+ updateLocalAuthorList(db.getLocalAuthors());
+ } catch(DbException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ } catch(InterruptedException e) {
+ LOG.info("Interrupted while waiting for service");
+ Thread.currentThread().interrupt();
+ }
+ }
+ });
+ }
+
+ private void updateLocalAuthorList(
+ final Collection localAuthors) {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ fromAdapter.clear();
+ for(LocalAuthor a : localAuthors) fromAdapter.add(a);
+ fromAdapter.sort(AuthorNameComparator.INSTANCE);
+ }
+ });
+ }
+
+ private void loadGroupList() {
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ serviceConnection.waitForStartup();
+ List groups = new ArrayList();
if(restricted) {
- postable.addAll(db.getLocalGroups());
+ groups.addAll(db.getLocalGroups());
} else {
for(Group g : db.getSubscriptions())
- if(!g.isRestricted()) postable.add(g);
+ if(!g.isRestricted()) groups.add(g);
}
- updateGroupList(Collections.unmodifiableList(postable));
+ groups = Collections.unmodifiableList(groups);
+ updateGroupList(groups);
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -156,13 +207,15 @@ implements OnClickListener, OnItemSelectedListener {
private void updateGroupList(final Collection groups) {
runOnUiThread(new Runnable() {
public void run() {
+ int index = -1;
for(Group g : groups) {
if(g.getId().equals(groupId)) {
group = g;
- spinner.setSelection(adapter.getCount());
+ index = toAdapter.getCount();
}
- adapter.add(g);
+ toAdapter.add(g);
}
+ if(index != -1) toSpinner.setSelection(index);
}
});
}
@@ -180,21 +233,45 @@ implements OnClickListener, OnItemSelectedListener {
unbindService(serviceConnection);
}
+ public void onItemSelected(AdapterView> parent, View view, int position,
+ long id) {
+ if(parent == fromSpinner) {
+ localAuthor = fromAdapter.getItem(position);
+ } else if(parent == toSpinner) {
+ group = toAdapter.getItem(position);
+ groupId = group.getId();
+ sendButton.setEnabled(true);
+ }
+ }
+
+ public void onNothingSelected(AdapterView> parent) {
+ if(parent == fromSpinner) {
+ localAuthor = null;
+ } else if(parent == toSpinner) {
+ group = null;
+ groupId = null;
+ sendButton.setEnabled(false);
+ }
+ }
+
public void onClick(View view) {
if(group == null) throw new IllegalStateException();
try {
- storeMessage(content.getText().toString().getBytes("UTF-8"));
+ storeMessage(localAuthor, group,
+ content.getText().toString().getBytes("UTF-8"));
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
finish();
}
- private void storeMessage(final byte[] body) {
- dbExecutor.execute(new Runnable() {
+ private void storeMessage(final LocalAuthor localAuthor, final Group group,
+ final byte[] body) {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
+ // FIXME: Anonymous/pseudonymous, restricted/unrestricted
Message m = messageFactory.createAnonymousMessage(parentId,
group, "text/plain", body);
db.addLocalGroupMessage(m);
@@ -213,17 +290,4 @@ implements OnClickListener, OnItemSelectedListener {
}
});
}
-
- public void onItemSelected(AdapterView> parent, View view, int position,
- long id) {
- group = adapter.getItem(position);
- groupId = group.getId();
- sendButton.setEnabled(true);
- }
-
- public void onNothingSelected(AdapterView> parent) {
- group = null;
- groupId = null;
- sendButton.setEnabled(false);
- }
}
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 5d2fb02ad..efc7251aa 100644
--- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
+++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
@@ -1,21 +1,42 @@
package net.sf.briar.android.invitation;
+import static java.util.logging.Level.WARNING;
+
+import java.util.Collection;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import net.sf.briar.android.AuthorNameComparator;
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.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
+import net.sf.briar.api.android.DatabaseUiExecutor;
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.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 android.widget.ArrayAdapter;
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;
@@ -33,6 +54,10 @@ implements InvitationListener {
private boolean localMatched = false, remoteMatched = false;
private String contactName = null;
+ // Fields that are accessed from DB threads must be volatile
+ @Inject private volatile DatabaseComponent db;
+ @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
+
@Override
public void onCreate(Bundle state) {
super.onCreate(null);
@@ -105,6 +130,10 @@ implements InvitationListener {
}
}
}
+
+ // Bind to the service so we can wait for the DB to be opened
+ bindService(new Intent(BriarService.class.getName()),
+ serviceConnection, 0);
}
@Override
@@ -156,6 +185,34 @@ implements InvitationListener {
setView(view);
}
+ void loadLocalAuthorList(final ArrayAdapter adapter) {
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ serviceConnection.waitForStartup();
+ updateLocalAuthorList(adapter, db.getLocalAuthors());
+ } catch(DbException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ } catch(InterruptedException e) {
+ LOG.info("Interrupted while waiting for service");
+ Thread.currentThread().interrupt();
+ }
+ }
+ });
+ }
+
+ private void updateLocalAuthorList(final ArrayAdapter adapter,
+ final Collection localAuthors) {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ adapter.clear();
+ for(LocalAuthor a : localAuthors) adapter.add(a);
+ adapter.sort(AuthorNameComparator.INSTANCE);
+ }
+ });
+ }
+
void setLocalAuthorId(AuthorId localAuthorId) {
this.localAuthorId = localAuthorId;
}
diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactView.java b/briar-android/src/net/sf/briar/android/invitation/AddContactView.java
index aaa6b1bc9..221998aab 100644
--- a/briar-android/src/net/sf/briar/android/invitation/AddContactView.java
+++ b/briar-android/src/net/sf/briar/android/invitation/AddContactView.java
@@ -9,8 +9,8 @@ abstract class AddContactView extends LinearLayout {
protected AddContactActivity container = null;
- AddContactView(Context context) {
- super(context);
+ AddContactView(Context ctx) {
+ super(ctx);
}
void init(AddContactActivity container) {
diff --git a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
index aa37cac92..94f532972 100644
--- a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
+++ b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
@@ -1,16 +1,25 @@
package net.sf.briar.android.invitation;
+import static android.view.Gravity.CENTER;
import net.sf.briar.R;
+import net.sf.briar.android.LocalAuthorNameSpinnerAdapter;
import net.sf.briar.android.widgets.CommonLayoutParams;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
import android.widget.TextView;
public class NetworkSetupView extends AddContactView
-implements WifiStateListener, BluetoothStateListener, OnClickListener {
+implements WifiStateListener, BluetoothStateListener, OnItemSelectedListener,
+OnClickListener {
+ private LocalAuthorNameSpinnerAdapter adapter = null;
+ private Spinner spinner = null;
private Button continueButton = null;
NetworkSetupView(Context ctx) {
@@ -20,13 +29,25 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
void populate() {
removeAllViews();
Context ctx = getContext();
- 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
+ LinearLayout innerLayout = new LinearLayout(ctx);
+ innerLayout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+ innerLayout.setOrientation(HORIZONTAL);
+ innerLayout.setGravity(CENTER);
+
+ TextView yourIdentity = new TextView(ctx);
+ yourIdentity.setTextSize(18);
+ yourIdentity.setPadding(10, 10, 10, 10);
+ yourIdentity.setText(R.string.your_identity);
+ innerLayout.addView(yourIdentity);
+
+ adapter = new LocalAuthorNameSpinnerAdapter(ctx);
+ spinner = new Spinner(ctx);
+ spinner.setAdapter(adapter);
+ spinner.setOnItemSelectedListener(this);
+ container.loadLocalAuthorList(adapter);
+ innerLayout.addView(spinner);
+ addView(innerLayout);
WifiWidget wifi = new WifiWidget(ctx);
wifi.init(this);
@@ -70,8 +91,16 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
else continueButton.setEnabled(false);
}
+ public void onItemSelected(AdapterView> parent, View view, int position,
+ long id) {
+ container.setLocalAuthorId(adapter.getItem(position).getId());
+ }
+
+ public void onNothingSelected(AdapterView> parent) {
+ container.setLocalAuthorId(null);
+ }
+
public void onClick(View view) {
- // Continue
container.setView(new InvitationCodeView(container));
}
}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
index 5e2cbacc1..a84117d80 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
@@ -6,7 +6,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -118,10 +117,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms");
- // Wait for the headers to be displayed in the UI
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, headers);
- latch.await();
+ // Display the headers in the UI
+ displayHeaders(headers);
} catch(NoSuchContactException e) {
if(LOG.isLoggable(INFO)) LOG.info("Contact removed");
finishOnUiThread();
@@ -130,25 +127,21 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
- private void displayHeaders(final CountDownLatch latch,
+ private void displayHeaders(
final Collection headers) {
runOnUiThread(new Runnable() {
public void run() {
- try {
- adapter.clear();
- for(PrivateMessageHeader h : headers) adapter.add(h);
- adapter.sort(AscendingHeaderComparator.INSTANCE);
- selectFirstUnread();
- } finally {
- latch.countDown();
- }
+ adapter.clear();
+ for(PrivateMessageHeader h : headers) adapter.add(h);
+ adapter.sort(AscendingHeaderComparator.INSTANCE);
+ selectFirstUnread();
}
});
}
@@ -199,7 +192,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
}
} else if(e instanceof MessageExpiredEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
- loadHeaders(); // FIXME: Don't reload everything
+ loadHeaders();
} else if(e instanceof PrivateMessageAddedEvent) {
PrivateMessageAddedEvent p = (PrivateMessageAddedEvent) e;
if(p.getContactId().equals(contactId)) {
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
index 3c2938da4..dfb5f7606 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -102,8 +101,6 @@ implements OnClickListener, DatabaseListener {
// Wait for the service to be bound and started
serviceConnection.waitForStartup();
// Load the contact list from the database
- Collection latches =
- new ArrayList();
long now = System.currentTimeMillis();
for(Contact c : db.getContacts()) {
try {
@@ -111,9 +108,7 @@ implements OnClickListener, DatabaseListener {
Collection headers =
db.getPrivateMessageHeaders(c.getId());
// Display the headers in the UI
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, c, headers);
- latches.add(latch);
+ displayHeaders(c, headers);
} catch(NoSuchContactException e) {
if(LOG.isLoggable(INFO))
LOG.info("Contact removed");
@@ -122,39 +117,33 @@ implements OnClickListener, DatabaseListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Full load took " + duration + " ms");
- // Wait for the headers to be displayed in the UI
- for(CountDownLatch latch : latches) latch.await();
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
});
}
- private void displayHeaders(final CountDownLatch latch, final Contact c,
+ private void displayHeaders(final Contact c,
final Collection headers) {
runOnUiThread(new Runnable() {
public void run() {
- try {
- // Remove the old item, if any
- ConversationListItem item = findConversation(c.getId());
- if(item != null) adapter.remove(item);
- // Add a new item if there are any headers to display
- if(!headers.isEmpty()) {
- List headerList =
- new ArrayList(headers);
- adapter.add(new ConversationListItem(c, headerList));
- adapter.sort(ConversationComparator.INSTANCE);
- }
- selectFirstUnread();
- } finally {
- latch.countDown();
+ // Remove the old item, if any
+ ConversationListItem item = findConversation(c.getId());
+ if(item != null) adapter.remove(item);
+ // Add a new item if there are any headers to display
+ if(!headers.isEmpty()) {
+ List headerList =
+ new ArrayList(headers);
+ adapter.add(new ConversationListItem(c, headerList));
+ adapter.sort(ConversationComparator.INSTANCE);
}
+ selectFirstUnread();
}
});
}
@@ -203,7 +192,7 @@ implements OnClickListener, DatabaseListener {
loadHeaders(((ContactRemovedEvent) e).getContactId());
} else if(e instanceof MessageExpiredEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
- loadHeaders(); // FIXME: Don't reload everything
+ loadHeaders();
} else if(e instanceof PrivateMessageAddedEvent) {
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
loadHeaders(((PrivateMessageAddedEvent) e).getContactId());
@@ -222,9 +211,7 @@ implements OnClickListener, DatabaseListener {
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Partial load took " + duration + " ms");
- CountDownLatch latch = new CountDownLatch(1);
- displayHeaders(latch, contact, headers);
- latch.await();
+ displayHeaders(contact, headers);
} catch(NoSuchContactException e) {
if(LOG.isLoggable(INFO)) LOG.info("Contact removed");
removeConversation(c);
@@ -233,7 +220,7 @@ implements OnClickListener, DatabaseListener {
LOG.log(WARNING, e.toString(), e);
} catch(InterruptedException e) {
if(LOG.isLoggable(INFO))
- LOG.info("Interrupted while loading headers");
+ LOG.info("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
}
diff --git a/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java
index 30a17a264..52c01ee4f 100644
--- a/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ReadPrivateMessageActivity.java
@@ -21,8 +21,8 @@ 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.BundleEncrypter;
+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.NoSuchMessageException;
import net.sf.briar.api.messaging.MessageId;
@@ -61,7 +61,7 @@ implements OnClickListener {
// 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;
private volatile MessageId messageId = null;
@Override
@@ -187,7 +187,7 @@ implements OnClickListener {
}
private void setReadInDatabase(final boolean read) {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
@@ -216,7 +216,7 @@ implements OnClickListener {
}
private void loadMessageBody() {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
diff --git a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
index 589cdc31e..838acb20d 100644
--- a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
@@ -19,11 +19,13 @@ 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.HorizontalSpace;
+import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
+import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
+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.messaging.Message;
import net.sf.briar.api.messaging.MessageFactory;
@@ -44,7 +46,7 @@ import android.widget.TextView;
import com.google.inject.Inject;
public class WritePrivateMessageActivity extends BriarActivity
-implements OnClickListener, OnItemSelectedListener {
+implements OnItemSelectedListener, OnClickListener {
private static final Logger LOG =
Logger.getLogger(WritePrivateMessageActivity.class.getName());
@@ -53,6 +55,7 @@ implements OnClickListener, OnItemSelectedListener {
new BriarServiceConnection();
@Inject private BundleEncrypter bundleEncrypter;
+ private TextView from = null;
private ContactNameSpinnerAdapter adapter = null;
private Spinner spinner = null;
private ImageButton sendButton = null;
@@ -60,8 +63,9 @@ implements OnClickListener, OnItemSelectedListener {
// 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;
+ private volatile LocalAuthor localAuthor = null;
private volatile ContactId contactId = null;
private volatile MessageId parentId = null;
@@ -79,33 +83,46 @@ implements OnClickListener, OnItemSelectedListener {
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
layout.setOrientation(VERTICAL);
- LinearLayout actionBar = new LinearLayout(this);
- actionBar.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
- actionBar.setOrientation(HORIZONTAL);
- actionBar.setGravity(CENTER_VERTICAL);
+ LinearLayout header = new LinearLayout(this);
+ header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+ header.setOrientation(HORIZONTAL);
+ header.setGravity(CENTER_VERTICAL);
+
+ from = new TextView(this);
+ from.setTextSize(18);
+ from.setMaxLines(1);
+ from.setPadding(10, 10, 10, 10);
+ from.setText(R.string.from);
+ header.addView(from);
+
+ header.addView(new HorizontalSpace(this));
+
+ sendButton = new ImageButton(this);
+ sendButton.setBackgroundResource(0);
+ sendButton.setImageResource(R.drawable.social_send_now);
+ sendButton.setEnabled(false); // Enabled after loading the local author
+ sendButton.setOnClickListener(this);
+ header.addView(sendButton);
+ layout.addView(header);
+
+ header = new LinearLayout(this);
+ header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+ header.setOrientation(HORIZONTAL);
+ header.setGravity(CENTER_VERTICAL);
TextView to = new TextView(this);
to.setTextSize(18);
to.setPadding(10, 10, 10, 10);
to.setText(R.string.to);
- actionBar.addView(to);
+ header.addView(to);
adapter = new ContactNameSpinnerAdapter(this);
spinner = new Spinner(this);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(this);
loadContactList();
- actionBar.addView(spinner);
-
- actionBar.addView(new HorizontalSpace(this));
-
- sendButton = new ImageButton(this);
- sendButton.setBackgroundResource(0);
- sendButton.setImageResource(R.drawable.social_send_now);
- sendButton.setEnabled(false);
- sendButton.setOnClickListener(this);
- actionBar.addView(sendButton);
- layout.addView(actionBar);
+ header.addView(spinner);
+ layout.addView(header);
content = new EditText(this);
content.setPadding(10, 10, 10, 10);
@@ -123,7 +140,7 @@ implements OnClickListener, OnItemSelectedListener {
}
private void loadContactList() {
- dbExecutor.execute(new Runnable() {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
@@ -142,11 +159,12 @@ implements OnClickListener, OnItemSelectedListener {
private void updateContactList(final Collection contacts) {
runOnUiThread(new Runnable() {
public void run() {
+ int index = -1;
for(Contact c : contacts) {
- if(c.getId().equals(contactId))
- spinner.setSelection(adapter.getCount());
+ if(c.getId().equals(contactId)) index = adapter.getCount();
adapter.add(c);
}
+ if(index != -1) spinner.setSelection(index);
}
});
}
@@ -164,18 +182,55 @@ implements OnClickListener, OnItemSelectedListener {
unbindService(serviceConnection);
}
+ public void onItemSelected(AdapterView> parent, View view, int position,
+ long id) {
+ Contact c = adapter.getItem(position);
+ loadLocalAuthor(c.getLocalAuthorId());
+ contactId = c.getId();
+ }
+
+ public void onNothingSelected(AdapterView> parent) {
+ contactId = null;
+ sendButton.setEnabled(false);
+ }
+
+ private void loadLocalAuthor(final AuthorId a) {
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ serviceConnection.waitForStartup();
+ localAuthor = db.getLocalAuthor(a);
+ runOnUiThread(new Runnable() {
+ public void run() {
+ sendButton.setEnabled(true);
+ }
+ });
+ } catch(DbException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ } catch(InterruptedException e) {
+ LOG.info("Interrupted while waiting for service");
+ Thread.currentThread().interrupt();
+ }
+ }
+ });
+ }
+
public void onClick(View view) {
- if(contactId == null) throw new IllegalStateException();
+ if(localAuthor == null || contactId == null)
+ throw new IllegalStateException();
try {
- storeMessage(content.getText().toString().getBytes("UTF-8"));
+ storeMessage(localAuthor, contactId,
+ content.getText().toString().getBytes("UTF-8"));
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
finish();
}
- private void storeMessage(final byte[] body) {
- dbExecutor.execute(new Runnable() {
+ private void storeMessage(final LocalAuthor localAuthor,
+ final ContactId contactId, final byte[] body) {
+ dbUiExecutor.execute(new Runnable() {
public void run() {
try {
serviceConnection.waitForStartup();
@@ -197,15 +252,4 @@ implements OnClickListener, OnItemSelectedListener {
}
});
}
-
- public void onItemSelected(AdapterView> parent, View view, int position,
- long id) {
- contactId = adapter.getItem(position).getId();
- sendButton.setEnabled(true);
- }
-
- public void onNothingSelected(AdapterView> parent) {
- contactId = null;
- sendButton.setEnabled(false);
- }
}
diff --git a/briar-api/src/net/sf/briar/api/Contact.java b/briar-api/src/net/sf/briar/api/Contact.java
index c86708276..4d9f558d6 100644
--- a/briar-api/src/net/sf/briar/api/Contact.java
+++ b/briar-api/src/net/sf/briar/api/Contact.java
@@ -4,11 +4,14 @@ public class Contact {
private final ContactId id;
private final Author author;
+ private final AuthorId localAuthorId;
private final long lastConnected;
- public Contact(ContactId id, Author author, long lastConnected) {
+ public Contact(ContactId id, Author author, AuthorId localAuthorId,
+ long lastConnected) {
this.id = id;
this.author = author;
+ this.localAuthorId = localAuthorId;
this.lastConnected = lastConnected;
}
@@ -20,6 +23,10 @@ public class Contact {
return author;
}
+ public AuthorId getLocalAuthorId() {
+ return localAuthorId;
+ }
+
public long getLastConnected() {
return lastConnected;
}
diff --git a/briar-api/src/net/sf/briar/api/db/event/MessageExpiredEvent.java b/briar-api/src/net/sf/briar/api/db/event/MessageExpiredEvent.java
index 1c1e11ef9..5f130f78a 100644
--- a/briar-api/src/net/sf/briar/api/db/event/MessageExpiredEvent.java
+++ b/briar-api/src/net/sf/briar/api/db/event/MessageExpiredEvent.java
@@ -1,22 +1,9 @@
package net.sf.briar.api.db.event;
-import java.util.Collection;
-
-import net.sf.briar.api.messaging.MessageId;
-
/**
* An event that is broadcast when one or messages expire from the database,
* potentially changing the database's retention time.
*/
public class MessageExpiredEvent extends DatabaseEvent {
- private final Collection expired;
-
- public MessageExpiredEvent(Collection expired) {
- this.expired = expired;
- }
-
- public Collection getMessageIds() {
- return expired;
- }
}
diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
index eb4da283d..d65eb6f00 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
@@ -2045,9 +2045,8 @@ DatabaseCleaner.Callback {
while(freeSpace < MIN_FREE_SPACE) {
boolean expired = expireMessages(BYTES_PER_SWEEP);
if(freeSpace < CRITICAL_FREE_SPACE && !expired) {
- // FIXME: Work out what to do here - the amount of free space
- // is critically low and there are no messages left to expire
- throw new Error("Disk space is critical");
+ // FIXME: Work out what to do here
+ throw new Error("Disk space is critically low");
}
Thread.yield();
freeSpace = db.getFreeSpace();
@@ -2086,7 +2085,7 @@ DatabaseCleaner.Callback {
messageLock.writeLock().unlock();
}
if(expired.isEmpty()) return false;
- callListeners(new MessageExpiredEvent(expired));
+ callListeners(new MessageExpiredEvent());
return true;
}
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index 59747daba..3abb7883e 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -1155,7 +1155,8 @@ abstract class JdbcDatabase implements Database {
PreparedStatement ps = null;
ResultSet rs = null;
try {
- String sql = "SELECT authorId, name, publicKey, lastConnected"
+ String sql = "SELECT authorId, name, publicKey, localAuthorId,"
+ + " lastConnected"
+ " FROM contacts AS c"
+ " JOIN connectionTimes AS ct"
+ " ON c.contactId = ct.contactId"
@@ -1167,11 +1168,12 @@ abstract class JdbcDatabase implements Database {
AuthorId authorId = new AuthorId(rs.getBytes(1));
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
- long lastConnected = rs.getLong(4);
+ AuthorId localAuthorId = new AuthorId(rs.getBytes(4));
+ long lastConnected = rs.getLong(5);
rs.close();
ps.close();
Author author = new Author(authorId, name, publicKey);
- return new Contact(c, author, lastConnected);
+ return new Contact(c, author, localAuthorId, lastConnected);
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
@@ -1205,7 +1207,7 @@ abstract class JdbcDatabase implements Database {
ResultSet rs = null;
try {
String sql = "SELECT c.contactId, authorId, name, publicKey,"
- + " lastConnected"
+ + " localAuthorId, lastConnected"
+ " FROM contacts AS c"
+ " JOIN connectionTimes AS ct"
+ " ON c.contactId = ct.contactId";
@@ -1217,9 +1219,11 @@ abstract class JdbcDatabase implements Database {
AuthorId authorId = new AuthorId(rs.getBytes(2));
String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4);
- long lastConnected = rs.getLong(5);
+ AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
+ long lastConnected = rs.getLong(6);
Author author = new Author(authorId, name, publicKey);
- contacts.add(new Contact(contactId, author, lastConnected));
+ contacts.add(new Contact(contactId, author, localAuthorId,
+ lastConnected));
}
rs.close();
ps.close();
diff --git a/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java b/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
index 9c51a1918..d72f05d16 100644
--- a/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
+++ b/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
@@ -134,6 +134,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
} else if(now >= creationTime) {
incomingNew.put(k, s);
} else {
+ // FIXME: Work out what to do here
throw new Error("Clock has moved backwards");
}
}
diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
index 7eeb1021a..d0a7f7299 100644
--- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
+++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
@@ -102,7 +102,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
transportProperties = new TransportProperties(Collections.singletonMap(
"foo", "bar"));
contactId = new ContactId(234);
- contact = new Contact(contactId, author, timestamp);
+ contact = new Contact(contactId, author, localAuthorId, timestamp);
endpoint = new Endpoint(contactId, transportId, 123, true);
temporarySecret = new TemporarySecret(contactId, transportId, 123,
false, 234, new byte[32], 345, 456, new byte[4]);