Various small tweaks and optimisations to message and forum activities.

This commit is contained in:
akwizgran
2013-12-22 01:57:56 +00:00
parent ff01b181bc
commit 88c7251ea2
10 changed files with 168 additions and 128 deletions

View File

@@ -46,7 +46,7 @@
<string name="exchanging_contact_details">Exchanging contact details\u2026</string> <string name="exchanging_contact_details">Exchanging contact details\u2026</string>
<string name="codes_do_not_match">Codes do not match</string> <string name="codes_do_not_match">Codes do not match</string>
<string name="interfering">This could mean that someone is trying to interfere with your connection</string> <string name="interfering">This could mean that someone is trying to interfere with your connection</string>
<string name="contact_added">Contact added</string> <string name="contact_added_toast">Contact added</string>
<string name="done_button">Done</string> <string name="done_button">Done</string>
<string name="messages_title">Messages</string> <string name="messages_title">Messages</string>
<string name="no_messages">(No messages)</string> <string name="no_messages">(No messages)</string>
@@ -81,4 +81,6 @@
<string name="no_contacts">You don\'t have any contacts. Add a contact now?</string> <string name="no_contacts">You don\'t have any contacts. Add a contact now?</string>
<string name="add_button">Add</string> <string name="add_button">Add</string>
<string name="cancel_button">Cancel</string> <string name="cancel_button">Cancel</string>
<string name="message_sent_toast">Message sent</string>
<string name="post_sent_toast">Post sent</string>
</resources> </resources>

View File

@@ -21,6 +21,7 @@ import net.sf.briar.R;
import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.android.invitation.AddContactActivity;
import net.sf.briar.android.util.HorizontalBorder; import net.sf.briar.android.util.HorizontalBorder;
import net.sf.briar.android.util.ListLoadingProgressBar; import net.sf.briar.android.util.ListLoadingProgressBar;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact; import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -35,6 +36,7 @@ import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.db.event.MessageAddedEvent; import net.sf.briar.api.db.event.MessageAddedEvent;
import net.sf.briar.api.db.event.MessageExpiredEvent; import net.sf.briar.api.db.event.MessageExpiredEvent;
import net.sf.briar.api.lifecycle.LifecycleManager; import net.sf.briar.api.lifecycle.LifecycleManager;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.transport.ConnectionListener; import net.sf.briar.api.transport.ConnectionListener;
import net.sf.briar.api.transport.ConnectionRegistry; import net.sf.briar.api.transport.ConnectionRegistry;
import roboguice.activity.RoboActivity; import roboguice.activity.RoboActivity;
@@ -42,12 +44,15 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
public class ContactListActivity extends RoboActivity public class ContactListActivity extends RoboActivity
implements OnClickListener, DatabaseListener, ConnectionListener { implements OnClickListener, OnItemClickListener, DatabaseListener,
ConnectionListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ContactListActivity.class.getName()); Logger.getLogger(ContactListActivity.class.getName());
@@ -76,7 +81,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
// Give me all the width and all the unused height // Give me all the width and all the unused height
list.setLayoutParams(MATCH_WRAP_1); list.setLayoutParams(MATCH_WRAP_1);
list.setAdapter(adapter); list.setAdapter(adapter);
list.setOnItemClickListener(adapter); list.setOnItemClickListener(this);
layout.addView(list); layout.addView(list);
// Show a progress bar while the list is loading // Show a progress bar while the list is loading
@@ -115,9 +120,10 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
Long lastConnected = times.get(c.getId()); Long lastConnected = times.get(c.getId());
if(lastConnected == null) continue; if(lastConnected == null) continue;
try { try {
GroupId inbox = db.getInboxGroupId(c.getId());
Collection<MessageHeader> headers = Collection<MessageHeader> headers =
db.getInboxMessageHeaders(c.getId()); db.getInboxMessageHeaders(c.getId());
displayContact(c, lastConnected, headers); displayContact(c, lastConnected, inbox, headers);
} catch(NoSuchContactException e) { } catch(NoSuchContactException e) {
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info("Contact removed"); LOG.info("Contact removed");
@@ -151,7 +157,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
} }
private void displayContact(final Contact c, final long lastConnected, private void displayContact(final Contact c, final long lastConnected,
final Collection<MessageHeader> headers) { final GroupId inbox, final Collection<MessageHeader> headers) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
list.setVisibility(VISIBLE); list.setVisibility(VISIBLE);
@@ -162,7 +168,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
if(item != null) adapter.remove(item); if(item != null) adapter.remove(item);
// Add a new item // Add a new item
adapter.add(new ContactListItem(c, connected, lastConnected, adapter.add(new ContactListItem(c, connected, lastConnected,
headers)); inbox, headers));
adapter.sort(ItemComparator.INSTANCE); adapter.sort(ItemComparator.INSTANCE);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} }
@@ -182,7 +188,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
int count = adapter.getCount(); int count = adapter.getCount();
for(int i = 0; i < count; i++) { for(int i = 0; i < count; i++) {
ContactListItem item = adapter.getItem(i); ContactListItem item = adapter.getItem(i);
if(item.getContactId().equals(c)) return item; if(item.getContact().getId().equals(c)) return item;
} }
return null; // Not found return null; // Not found
} }
@@ -198,6 +204,21 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
startActivity(new Intent(this, AddContactActivity.class)); startActivity(new Intent(this, AddContactActivity.class));
} }
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ContactListItem item = adapter.getItem(position);
ContactId contactId = item.getContact().getId();
String contactName = item.getContact().getAuthor().getName();
GroupId inbox = item.getInboxGroupId();
AuthorId localAuthorId = item.getContact().getLocalAuthorId();
Intent i = new Intent(this, ConversationActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.GROUP_ID", inbox.getBytes());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
startActivity(i);
}
public void eventOccurred(DatabaseEvent e) { public void eventOccurred(DatabaseEvent e) {
if(e instanceof ContactAddedEvent) { if(e instanceof ContactAddedEvent) {
loadContacts(); loadContacts();
@@ -257,7 +278,10 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
ContactListItem item = findItem(c); ContactListItem item = findItem(c);
if(item != null) adapter.remove(item); if(item != null) {
adapter.remove(item);
adapter.notifyDataSetChanged();
}
} }
}); });
} }
@@ -288,8 +312,9 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
private static final ItemComparator INSTANCE = new ItemComparator(); private static final ItemComparator INSTANCE = new ItemComparator();
public int compare(ContactListItem a, ContactListItem b) { public int compare(ContactListItem a, ContactListItem b) {
return String.CASE_INSENSITIVE_ORDER.compare(a.getContactName(), String aName = a.getContact().getAuthor().getName();
b.getContactName()); String bName = b.getContact().getAuthor().getName();
return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
} }
} }
} }

View File

@@ -8,21 +8,17 @@ import java.util.ArrayList;
import net.sf.briar.R; import net.sf.briar.R;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.text.Html; import android.text.Html;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
class ContactListAdapter extends ArrayAdapter<ContactListItem> class ContactListAdapter extends ArrayAdapter<ContactListItem> {
implements OnItemClickListener {
ContactListAdapter(Context ctx) { ContactListAdapter(Context ctx) {
super(ctx, android.R.layout.simple_expandable_list_item_1, super(ctx, android.R.layout.simple_expandable_list_item_1,
@@ -54,7 +50,7 @@ implements OnItemClickListener {
name.setMaxLines(1); name.setMaxLines(1);
name.setPadding(0, 10, 10, 10); name.setPadding(0, 10, 10, 10);
int unread = item.getUnreadCount(); int unread = item.getUnreadCount();
String contactName = item.getContactName(); String contactName = item.getContact().getAuthor().getName();
if(unread > 0) name.setText(contactName + " (" + unread + ")"); if(unread > 0) name.setText(contactName + " (" + unread + ")");
else name.setText(contactName); else name.setText(contactName);
layout.addView(name); layout.addView(name);
@@ -74,15 +70,4 @@ implements OnItemClickListener {
return layout; return layout;
} }
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ContactListItem item = getItem(position);
Intent i = new Intent(getContext(), ConversationActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", item.getContactId().getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", item.getContactName());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID",
item.getLocalAuthorId().getBytes());
getContext().startActivity(i);
}
} }

View File

@@ -2,15 +2,15 @@ package net.sf.briar.android.contact;
import java.util.Collection; import java.util.Collection;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.Contact; import net.sf.briar.api.Contact;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.MessageHeader;
import net.sf.briar.api.messaging.GroupId;
// This class is not thread-safe // This class is not thread-safe
class ContactListItem { class ContactListItem {
private final Contact contact; private final Contact contact;
private final GroupId inbox;
private boolean connected; private boolean connected;
private long lastConnected; private long lastConnected;
private boolean empty; private boolean empty;
@@ -18,8 +18,9 @@ class ContactListItem {
private int unread; private int unread;
ContactListItem(Contact contact, boolean connected, long lastConnected, ContactListItem(Contact contact, boolean connected, long lastConnected,
Collection<MessageHeader> headers) { GroupId inbox, Collection<MessageHeader> headers) {
this.contact = contact; this.contact = contact;
this.inbox = inbox;
this.connected = connected; this.connected = connected;
this.lastConnected = lastConnected; this.lastConnected = lastConnected;
setHeaders(headers); setHeaders(headers);
@@ -41,12 +42,8 @@ class ContactListItem {
return contact; return contact;
} }
ContactId getContactId() { GroupId getInboxGroupId() {
return contact.getId(); return inbox;
}
String getContactName() {
return contact.getAuthor().getName();
} }
long getLastConnected() { long getLastConnected() {
@@ -65,10 +62,6 @@ class ContactListItem {
this.connected = connected; this.connected = connected;
} }
AuthorId getLocalAuthorId() {
return contact.getLocalAuthorId();
}
boolean isEmpty() { boolean isEmpty() {
return empty; return empty;
} }

View File

@@ -18,6 +18,7 @@ import javax.inject.Inject;
import net.sf.briar.R; import net.sf.briar.R;
import net.sf.briar.android.util.HorizontalBorder; import net.sf.briar.android.util.HorizontalBorder;
import net.sf.briar.android.util.ListLoadingProgressBar; import net.sf.briar.android.util.ListLoadingProgressBar;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
@@ -60,6 +61,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
@Inject private volatile LifecycleManager lifecycleManager; @Inject private volatile LifecycleManager lifecycleManager;
private volatile ContactId contactId = null; private volatile ContactId contactId = null;
private volatile GroupId groupId = null; private volatile GroupId groupId = null;
private volatile AuthorId localAuthorId = null;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
@@ -72,6 +74,12 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME"); contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException(); if(contactName == null) throw new IllegalStateException();
setTitle(contactName); setTitle(contactName);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b == null) throw new IllegalStateException();
groupId = new GroupId(b);
b = i.getByteArrayExtra("net.sf.briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
LinearLayout layout = new LinearLayout(this); LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(MATCH_MATCH); layout.setLayoutParams(MATCH_MATCH);
@@ -116,7 +124,6 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
groupId = db.getInboxGroup(contactId);
Collection<MessageHeader> headers = Collection<MessageHeader> headers =
db.getInboxMessageHeaders(contactId); db.getInboxMessageHeaders(contactId);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
@@ -201,8 +208,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
}); });
} }
} else if(e instanceof MessageAddedEvent) { } else if(e instanceof MessageAddedEvent) {
ContactId source = ((MessageAddedEvent) e).getContactId(); GroupId g = ((MessageAddedEvent) e).getGroup().getId();
if(source == null || source.equals(contactId)) { if(g.equals(groupId)) {
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading"); if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
loadHeaders(); loadHeaders();
} }
@@ -214,8 +221,9 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
public void onClick(View view) { public void onClick(View view) {
Intent i = new Intent(this, WritePrivateMessageActivity.class); Intent i = new Intent(this, WritePrivateMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt()); i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes()); i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
startActivity(i); startActivity(i);
} }
@@ -229,7 +237,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
Intent i = new Intent(this, ReadPrivateMessageActivity.class); Intent i = new Intent(this, ReadPrivateMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt()); i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", contactName); i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.GROUP_ID", header.getGroupId().getBytes()); i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
i.putExtra("net.sf.briar.AUTHOR_NAME", header.getAuthor().getName()); i.putExtra("net.sf.briar.AUTHOR_NAME", header.getAuthor().getName());
i.putExtra("net.sf.briar.MESSAGE_ID", header.getId().getBytes()); i.putExtra("net.sf.briar.MESSAGE_ID", header.getId().getBytes());
i.putExtra("net.sf.briar.CONTENT_TYPE", header.getContentType()); i.putExtra("net.sf.briar.CONTENT_TYPE", header.getContentType());

View File

@@ -20,7 +20,7 @@ import javax.inject.Inject;
import net.sf.briar.R; import net.sf.briar.R;
import net.sf.briar.android.util.HorizontalBorder; import net.sf.briar.android.util.HorizontalBorder;
import net.sf.briar.android.util.HorizontalSpace; import net.sf.briar.android.util.HorizontalSpace;
import net.sf.briar.api.ContactId; import net.sf.briar.api.AuthorId;
import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
@@ -50,8 +50,9 @@ implements OnClickListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ReadPrivateMessageActivity.class.getName()); Logger.getLogger(ReadPrivateMessageActivity.class.getName());
private ContactId contactId = null; private String contactName = null;
private boolean read; private AuthorId localAuthorId = null;
private boolean read = false;
private ImageButton readButton = null, prevButton = null, nextButton = null; private ImageButton readButton = null, prevButton = null, nextButton = null;
private ImageButton replyButton = null; private ImageButton replyButton = null;
private TextView content = null; private TextView content = null;
@@ -69,15 +70,15 @@ implements OnClickListener {
super.onCreate(state); super.onCreate(state);
Intent i = getIntent(); Intent i = getIntent();
int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1); contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(id == -1) throw new IllegalStateException();
contactId = new ContactId(id);
String contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException(); if(contactName == null) throw new IllegalStateException();
setTitle(contactName); setTitle(contactName);
byte[] b = i.getByteArrayExtra("net.sf.briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME"); String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
if(authorName == null) throw new IllegalStateException(); if(authorName == null) throw new IllegalStateException();
byte[] b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID"); b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException(); if(b == null) throw new IllegalStateException();
messageId = new MessageId(b); messageId = new MessageId(b);
b = i.getByteArrayExtra("net.sf.briar.GROUP_ID"); b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
@@ -266,8 +267,10 @@ implements OnClickListener {
finish(); finish();
} else if(view == replyButton) { } else if(view == replyButton) {
Intent i = new Intent(this, WritePrivateMessageActivity.class); Intent i = new Intent(this, WritePrivateMessageActivity.class);
i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt()); i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes()); i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
i.putExtra("net.sf.briar.LOCAL_AUTHOR_ID",
localAuthorId.getBytes());
i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes()); i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
i.putExtra("net.sf.briar.TIMESTAMP", timestamp); i.putExtra("net.sf.briar.TIMESTAMP", timestamp);
startActivity(i); startActivity(i);

View File

@@ -5,6 +5,7 @@ import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.CENTER_VERTICAL;
import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL; import static android.widget.LinearLayout.VERTICAL;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP; import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
@@ -19,10 +20,10 @@ import javax.inject.Inject;
import net.sf.briar.R; import net.sf.briar.R;
import net.sf.briar.android.util.HorizontalSpace; import net.sf.briar.android.util.HorizontalSpace;
import net.sf.briar.api.Contact; import net.sf.briar.api.AuthorId;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.LocalAuthor; import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.crypto.CryptoExecutor;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.NoSuchContactException; import net.sf.briar.api.db.NoSuchContactException;
@@ -44,6 +45,7 @@ import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
public class WritePrivateMessageActivity extends RoboActivity public class WritePrivateMessageActivity extends RoboActivity
implements OnClickListener { implements OnClickListener {
@@ -59,12 +61,13 @@ implements OnClickListener {
@Inject private volatile DatabaseComponent db; @Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@Inject private volatile LifecycleManager lifecycleManager; @Inject private volatile LifecycleManager lifecycleManager;
@Inject @CryptoExecutor private volatile Executor cryptoExecutor;
@Inject private volatile MessageFactory messageFactory; @Inject private volatile MessageFactory messageFactory;
private volatile ContactId contactId = null; private volatile String contactName = null;
private volatile GroupId groupId = null; private volatile GroupId groupId = null;
private volatile AuthorId localAuthorId = null;
private volatile MessageId parentId = null; private volatile MessageId parentId = null;
private volatile long timestamp = -1; private volatile long timestamp = -1;
private volatile Contact contact = null;
private volatile LocalAuthor localAuthor = null; private volatile LocalAuthor localAuthor = null;
private volatile Group group = null; private volatile Group group = null;
@@ -73,12 +76,14 @@ implements OnClickListener {
super.onCreate(state); super.onCreate(state);
Intent i = getIntent(); Intent i = getIntent();
int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1); contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(id == -1) throw new IllegalStateException(); if(contactName == null) throw new IllegalStateException();
contactId = new ContactId(id);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID"); byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b == null) throw new IllegalStateException(); if(b == null) throw new IllegalStateException();
groupId = new GroupId(b); groupId = new GroupId(b);
b = i.getByteArrayExtra("net.sf.briar.LOCAL_AUTHOR_ID");
if(b == null) throw new IllegalStateException();
localAuthorId = new AuthorId(b);
b = i.getByteArrayExtra("net.sf.briar.PARENT_ID"); b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
if(b != null) parentId = new MessageId(b); if(b != null) parentId = new MessageId(b);
timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1); timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
@@ -111,7 +116,8 @@ implements OnClickListener {
to = new TextView(this); to = new TextView(this);
to.setTextSize(18); to.setTextSize(18);
to.setPadding(10, 0, 10, 10); to.setPadding(10, 0, 10, 10);
to.setText(R.string.to); String format = getResources().getString(R.string.format_to);
to.setText(String.format(format, contactName));
layout.addView(to); layout.addView(to);
content = new EditText(this); content = new EditText(this);
@@ -127,22 +133,21 @@ implements OnClickListener {
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
loadAuthorsAndGroup(); loadAuthorAndGroup();
} }
private void loadAuthorsAndGroup() { private void loadAuthorAndGroup() {
dbUiExecutor.execute(new Runnable() { dbUiExecutor.execute(new Runnable() {
public void run() { public void run() {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
contact = db.getContact(contactId); localAuthor = db.getLocalAuthor(localAuthorId);
localAuthor = db.getLocalAuthor(contact.getLocalAuthorId());
group = db.getGroup(groupId); group = db.getGroup(groupId);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms"); LOG.info("Load took " + duration + " ms");
displayAuthors(); displayLocalAuthor();
} catch(NoSuchContactException e) { } catch(NoSuchContactException e) {
finish(); finish();
} catch(NoSuchSubscriptionException e) { } catch(NoSuchSubscriptionException e) {
@@ -158,42 +163,54 @@ implements OnClickListener {
}); });
} }
private void displayAuthors() { private void displayLocalAuthor() {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
Resources res = getResources(); Resources res = getResources();
String format = res.getString(R.string.format_from); String format = res.getString(R.string.format_from);
String name = localAuthor.getName(); String name = localAuthor.getName();
from.setText(String.format(format, name)); from.setText(String.format(format, name));
format = res.getString(R.string.format_to);
name = contact.getAuthor().getName();
to.setText(String.format(format, name));
sendButton.setEnabled(true); sendButton.setEnabled(true);
} }
}); });
} }
public void onClick(View view) { public void onClick(View view) {
if(contact == null || localAuthor == null) if(localAuthor == null) throw new IllegalStateException();
throw new IllegalStateException();
try { try {
storeMessage(content.getText().toString().getBytes("UTF-8")); createMessage(content.getText().toString().getBytes("UTF-8"));
} catch(UnsupportedEncodingException e) { } catch(UnsupportedEncodingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Toast.makeText(this, R.string.message_sent_toast, LENGTH_LONG).show();
finish(); finish();
} }
private void storeMessage(final byte[] body) { private void createMessage(final byte[] body) {
cryptoExecutor.execute(new Runnable() {
public void run() {
// Don't use an earlier timestamp than the parent
long time = System.currentTimeMillis();
time = Math.max(time, timestamp + 1);
Message m;
try {
m = messageFactory.createAnonymousMessage(parentId, group,
"text/plain", time, body);
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
} catch(IOException e) {
throw new RuntimeException(e);
}
storeMessage(m);
}
});
}
private void storeMessage(final Message m) {
dbUiExecutor.execute(new Runnable() { dbUiExecutor.execute(new Runnable() {
public void run() { public void run() {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
// Don't use an earlier timestamp than the parent
long time = System.currentTimeMillis();
time = Math.max(time, timestamp + 1);
Message m = messageFactory.createAnonymousMessage(parentId,
group, "text/plain", time, body);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
db.addLocalMessage(m); db.addLocalMessage(m);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
@@ -202,14 +219,10 @@ implements OnClickListener {
} catch(DbException e) { } catch(DbException e) {
if(LOG.isLoggable(WARNING)) if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e); LOG.log(WARNING, e.toString(), e);
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
} catch(InterruptedException e) { } catch(InterruptedException e) {
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info("Interrupted while waiting for database"); LOG.info("Interrupted while waiting for database");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch(IOException e) {
throw new RuntimeException(e);
} }
} }
}); });

View File

@@ -76,11 +76,11 @@ implements OnClickListener {
b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID"); b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
if(b == null) throw new IllegalStateException(); if(b == null) throw new IllegalStateException();
messageId = new MessageId(b); messageId = new MessageId(b);
String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE"); String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
if(contentType == null) throw new IllegalStateException(); if(contentType == null) throw new IllegalStateException();
timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1); timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
if(timestamp == -1) throw new IllegalStateException(); if(timestamp == -1) throw new IllegalStateException();
String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
if(state == null) { if(state == null) {
read = false; read = false;

View File

@@ -5,11 +5,13 @@ import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.CENTER_VERTICAL;
import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL; import static android.widget.LinearLayout.VERTICAL;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP; import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -27,6 +29,7 @@ import net.sf.briar.api.AuthorId;
import net.sf.briar.api.LocalAuthor; import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.DatabaseUiExecutor; import net.sf.briar.api.android.DatabaseUiExecutor;
import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.CryptoExecutor;
import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.crypto.PrivateKey; import net.sf.briar.api.crypto.PrivateKey;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
@@ -51,6 +54,7 @@ import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
public class WriteGroupPostActivity extends RoboActivity public class WriteGroupPostActivity extends RoboActivity
implements OnItemSelectedListener, OnClickListener { implements OnItemSelectedListener, OnClickListener {
@@ -58,8 +62,6 @@ implements OnItemSelectedListener, OnClickListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(WriteGroupPostActivity.class.getName()); Logger.getLogger(WriteGroupPostActivity.class.getName());
@Inject private CryptoComponent crypto;
@Inject private MessageFactory messageFactory;
private LocalAuthorSpinnerAdapter adapter = null; private LocalAuthorSpinnerAdapter adapter = null;
private Spinner spinner = null; private Spinner spinner = null;
private ImageButton sendButton = null; private ImageButton sendButton = null;
@@ -72,6 +74,9 @@ implements OnItemSelectedListener, OnClickListener {
@Inject private volatile DatabaseComponent db; @Inject private volatile DatabaseComponent db;
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor; @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
@Inject private volatile LifecycleManager lifecycleManager; @Inject private volatile LifecycleManager lifecycleManager;
@Inject @CryptoExecutor private volatile Executor cryptoExecutor;
@Inject private volatile CryptoComponent crypto;
@Inject private volatile MessageFactory messageFactory;
private volatile MessageId parentId = null; private volatile MessageId parentId = null;
private volatile long timestamp = -1; private volatile long timestamp = -1;
private volatile LocalAuthor localAuthor = null; private volatile LocalAuthor localAuthor = null;
@@ -207,62 +212,67 @@ implements OnItemSelectedListener, OnClickListener {
byte[] b = localAuthorId.getBytes(); byte[] b = localAuthorId.getBytes();
state.putByteArray("net.sf.briar.LOCAL_AUTHOR_ID", b); state.putByteArray("net.sf.briar.LOCAL_AUTHOR_ID", b);
} }
if(groupId != null) {
byte[] b = groupId.getBytes();
state.putByteArray("net.sf.briar.GROUP_ID", b);
}
} }
public void onItemSelected(AdapterView<?> parent, View view, int position, public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) { long id) {
LocalAuthorItem item = adapter.getItem(position); LocalAuthorItem item = adapter.getItem(position);
if(item == LocalAuthorItem.ANONYMOUS) { if(item == LocalAuthorItem.ANONYMOUS) {
localAuthor = null; localAuthor = null;
localAuthorId = null; localAuthorId = null;
} else if(item == LocalAuthorItem.NEW) { } else if(item == LocalAuthorItem.NEW) {
localAuthor = null; localAuthor = null;
localAuthorId = null; localAuthorId = null;
startActivity(new Intent(this, CreateIdentityActivity.class)); startActivity(new Intent(this, CreateIdentityActivity.class));
} else { } else {
localAuthor = item.getLocalAuthor(); localAuthor = item.getLocalAuthor();
localAuthorId = localAuthor.getId(); localAuthorId = localAuthor.getId();
} }
} }
public void onNothingSelected(AdapterView<?> parent) { public void onNothingSelected(AdapterView<?> parent) {
localAuthor = null; localAuthor = null;
localAuthorId = null; localAuthorId = null;
} }
public void onClick(View view) { public void onClick(View view) {
if(group == null) throw new IllegalStateException(); if(group == null) throw new IllegalStateException();
try { try {
byte[] b = content.getText().toString().getBytes("UTF-8"); createMessage(content.getText().toString().getBytes("UTF-8"));
storeMessage(createMessage(b)); } catch(UnsupportedEncodingException e) {
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
} catch(IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Toast.makeText(this, R.string.post_sent_toast, LENGTH_LONG).show();
finish(); finish();
} }
// FIXME: This should happen on a CryptoExecutor thread private void createMessage(final byte[] body) {
private Message createMessage(byte[] body) throws IOException, cryptoExecutor.execute(new Runnable() {
GeneralSecurityException { public void run() {
// Don't use an earlier timestamp than the parent // Don't use an earlier timestamp than the parent
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
time = Math.max(time, timestamp + 1); time = Math.max(time, timestamp + 1);
if(localAuthor == null) { Message m;
return messageFactory.createAnonymousMessage(parentId, group, try {
"text/plain", time, body); if(localAuthor == null) {
} else { m = messageFactory.createAnonymousMessage(parentId,
KeyParser keyParser = crypto.getSignatureKeyParser(); group, "text/plain", time, body);
byte[] authorKeyBytes = localAuthor.getPrivateKey(); } else {
PrivateKey authorKey = keyParser.parsePrivateKey(authorKeyBytes); KeyParser keyParser = crypto.getSignatureKeyParser();
return messageFactory.createPseudonymousMessage(parentId, byte[] b = localAuthor.getPrivateKey();
group, localAuthor, authorKey, "text/plain", time, body); PrivateKey authorKey = keyParser.parsePrivateKey(b);
} m = messageFactory.createPseudonymousMessage(parentId,
group, localAuthor, authorKey, "text/plain",
time, body);
}
} catch(GeneralSecurityException e) {
throw new RuntimeException(e);
} catch(IOException e) {
throw new RuntimeException(e);
}
storeMessage(m);
}
});
} }
private void storeMessage(final Message m) { private void storeMessage(final Message m) {

View File

@@ -169,7 +169,7 @@ implements InvitationListener {
} }
private void showToastAndFinish() { private void showToastAndFinish() {
Toast.makeText(this, R.string.contact_added, LENGTH_LONG).show(); Toast.makeText(this, R.string.contact_added_toast, LENGTH_LONG).show();
finish(); finish();
} }