diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 550e381e74593eb97a2e02aa84abebbf5c52da62..b43e6620e1194e50c1a2470b51adc24fb7b96d8e 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -13,15 +13,15 @@ <string name="contact_connected">Connected</string> <string name="format_contact_last_connected">Last connected <br /> %1$s</string> <string name="add_contact_title">Add a Contact</string> - <string name="choose_identity">Choose an identity to use with this contact:</string> - <string name="wifi_not_available">Wi-Fi is not available on this device</string> + <string name="your_identity">Your identity: </string> + <string name="wifi_not_available">Wi-Fi is NOT AVAILABLE</string> <string name="wifi_disabled">Wi-Fi is OFF</string> <string name="wifi_disconnected">Wi-Fi is DISCONNECTED</string> - <string name="format_wifi_connected">Wi-Fi is CONNECTED to %1$s</string> - <string name="bluetooth_not_available">Bluetooth is not available on this device</string> + <string name="format_wifi_connected">Wi-Fi is connected to %1$s</string> + <string name="bluetooth_not_available">Bluetooth is NOT AVAILABLE</string> <string name="bluetooth_disabled">Bluetooth is OFF</string> <string name="bluetooth_not_discoverable">Bluetooth is NOT DISCOVERABLE</string> - <string name="bluetooth_enabled">Bluetooth is DISCOVERABLE</string> + <string name="bluetooth_enabled">Bluetooth is discoverable</string> <string name="continue_button">Continue</string> <string name="your_invitation_code">Your invitation code is</string> <string name="enter_invitation_code">Please enter your contact\'s invitation code:</string> @@ -43,7 +43,8 @@ <string name="format_from">From: %1$s</string> <string name="format_to">To: %1$s</string> <string name="compose_message_title">New Message</string> - <string name="to">To:</string> + <string name="from">From: </string> + <string name="to">To: </string> <string name="anonymous">(Anonymous)</string> <string name="groups_title">Groups</string> <string name="compose_group_title">New Post</string> 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 0000000000000000000000000000000000000000..acde1829d838efa2a0b7cdfb7658e483755618f5 --- /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<Author> { + + 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 0000000000000000000000000000000000000000..ffeb3feb9cc30ccbc23de9c5fb10a24828de2408 --- /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<LocalAuthor> +implements SpinnerAdapter { + + public LocalAuthorNameSpinnerAdapter(Context context) { + super(context, android.R.layout.simple_spinner_item, + new ArrayList<LocalAuthor>()); + } + + @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 294f18da96e86ff7a9f136a7b87e5e5afb3b1a84..32bbb5a9cf68a72f0153d0318fb58a5239bb03a4 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<GroupMessageHeader> headers) { + private void displayHeaders(final Collection<GroupMessageHeader> 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 f173274fa882f27e3e2296acc42cbcfe97f6420d..baa57973b4c1189f0a46ea121ede3bbc3941dee8 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<CountDownLatch> latches = - new ArrayList<CountDownLatch>(); long now = System.currentTimeMillis(); for(Group g : db.getSubscriptions()) { // Filter out restricted/unrestricted groups @@ -141,9 +138,7 @@ implements OnClickListener, DatabaseListener { Collection<GroupMessageHeader> 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<GroupMessageHeader> 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<GroupMessageHeader> headerList = - new ArrayList<GroupMessageHeader>(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<GroupMessageHeader> headerList = + new ArrayList<GroupMessageHeader>(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 b8b33637ff9f4768df2bff11c97782d4f7bd56f8..48b925723c4078766e186bf102c64d7b7486e8dd 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 1668c92eda187bb02e03c871878c5877da762519..1b1be08a0c0279a742b344d9a7c957dcc3bca80a 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 to = new TextView(this); - to.setTextSize(18); - to.setPadding(10, 10, 10, 10); - to.setText(R.string.to); - actionBar.addView(to); + TextView from = new TextView(this); + from.setTextSize(18); + from.setPadding(10, 10, 10, 10); + from.setText(R.string.from); + header.addView(from); - adapter = new GroupNameSpinnerAdapter(this); - spinner = new Spinner(this); - spinner.setAdapter(adapter); - spinner.setOnItemSelectedListener(this); - loadGroupList(); - actionBar.addView(spinner); + fromAdapter = new LocalAuthorNameSpinnerAdapter(this); + fromSpinner = new Spinner(this); + fromSpinner.setOnItemSelectedListener(this); + loadLocalAuthorList(); + header.addView(fromSpinner); - actionBar.addView(new HorizontalSpace(this)); + header.addView(new HorizontalSpace(this)); sendButton = new ImageButton(this); sendButton.setBackgroundResource(0); sendButton.setImageResource(R.drawable.social_send_now); - sendButton.setEnabled(false); + sendButton.setEnabled(false); // Enabled when a group is selected sendButton.setOnClickListener(this); - actionBar.addView(sendButton); - layout.addView(actionBar); + 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); + header.addView(to); + + toAdapter = new GroupNameSpinnerAdapter(this); + toSpinner = new Spinner(this); + toSpinner.setAdapter(toAdapter); + toSpinner.setOnItemSelectedListener(this); + loadGroupList(); + 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 loadLocalAuthorList() { + dbUiExecutor.execute(new Runnable() { + public void run() { + try { + serviceConnection.waitForStartup(); + 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<LocalAuthor> localAuthors) { + runOnUiThread(new Runnable() { + public void run() { + fromAdapter.clear(); + for(LocalAuthor a : localAuthors) fromAdapter.add(a); + fromAdapter.sort(AuthorNameComparator.INSTANCE); + } + }); + } + private void loadGroupList() { - dbExecutor.execute(new Runnable() { + dbUiExecutor.execute(new Runnable() { public void run() { try { serviceConnection.waitForStartup(); - List<Group> postable = new ArrayList<Group>(); + List<Group> groups = new ArrayList<Group>(); 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<Group> 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 5d2fb02ad9401fc633984fb3816931fd84218386..efc7251aa682c514ddc5d7cc78da76cba8d9476a 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<LocalAuthor> 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<LocalAuthor> adapter, + final Collection<LocalAuthor> 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 aaa6b1bc97d4dc883ae576f5a4c9808cc38824d5..221998aab17df01a724ab10cace742c31bac560d 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 aa37cac92c17d77ac0b67a86477dc9f967ea823a..94f53297239c9f032d172a521e52efb670a2dd6a 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 5e2cbacc1d14adeb5f25e68d41ba36ad692a220a..a84117d80bd1d7efb01b12c2b2521bd5b9fc661b 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<PrivateMessageHeader> 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 3c2938da420510c94cf01914094fcddc4244df48..dfb5f76064d6f6a9d8bcfa6432678554098a6225 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<CountDownLatch> latches = - new ArrayList<CountDownLatch>(); long now = System.currentTimeMillis(); for(Contact c : db.getContacts()) { try { @@ -111,9 +108,7 @@ implements OnClickListener, DatabaseListener { Collection<PrivateMessageHeader> 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<PrivateMessageHeader> 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<PrivateMessageHeader> headerList = - new ArrayList<PrivateMessageHeader>(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<PrivateMessageHeader> headerList = + new ArrayList<PrivateMessageHeader>(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 30a17a264bafe5526a1c83a8eaa79bcf622deb4a..52c01ee4fb9afcc173770b3bc9d13480a45469e6 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 589cdc31ef974b6dbb0673f5fff611d0b0c75445..838acb20d8f53d76759bbd84fb4128b21a5eb777 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<Contact> 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 c86708276ed5f68d3096ad24943bfe42fe855b4d..4d9f558d6d37d1f041793b6dc9eab31171c734f5 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 1c1e11ef914f2582d1369bf744f27f744ab45999..5f130f78a7f5fb00f80c0197549168c2d69c2e02 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<MessageId> expired; - - public MessageExpiredEvent(Collection<MessageId> expired) { - this.expired = expired; - } - - public Collection<MessageId> 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 eb4da283ddcd2971533631b64c548a958012362c..d65eb6f0010690f92127898bbf26a3ac75bb2fbf 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 59747daba35d71ef1b1a6b630867933179838c45..3abb7883e408596e1ca717c21ee52399577c058c 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<Connection> { 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<Connection> { 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<Connection> { 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<Connection> { 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 9c51a19181576b85249ab4b97d489204b4d79a5d..d72f05d1650fe43e4f014901a3457b72e9b2b147 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 7eeb1021a5823c6b59088a7fc896ecbe035fccf5..d0a7f7299de0d47ba2ff89947a0570a2e5da7088 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]);