diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java index dc1628088dee0ae382ed089fa9b8c09b9671be11..1475608ec6d7de320a54b8345441294272ccdac2 100644 --- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java @@ -12,6 +12,7 @@ import android.widget.TextView; import org.briarproject.R; import org.briarproject.api.contact.ContactId; import org.briarproject.api.identity.Author; +import org.briarproject.api.sync.GroupId; import org.briarproject.util.StringUtils; import java.util.List; @@ -67,7 +68,7 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B return contacts.get(position); } - public void updateItem(int position, ContactListItem item) { + void updateItem(int position, ContactListItem item) { contacts.updateItemAt(position, item); } @@ -75,7 +76,7 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B return contacts.indexOf(c); } - public int findItemPosition(ContactId c) { + int findItemPosition(ContactId c) { int count = getItemCount(); for (int i = 0; i < count; i++) { ContactListItem item = getItem(i); @@ -84,6 +85,15 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B return INVALID_POSITION; // Not found } + int findItemPosition(GroupId g) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + ContactListItem item = getItem(i); + if (item.getGroupId().equals(g)) return i; + } + return INVALID_POSITION; // Not found + } + public void addAll(List<ContactListItem> contacts) { this.contacts.addAll(contacts); } @@ -130,7 +140,7 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B } } - protected int compareByTime(ContactListItem c1, ContactListItem c2) { + int compareByTime(ContactListItem c1, ContactListItem c2) { long time1 = c1.getTimestamp(); long time2 = c2.getTimestamp(); if (time1 < time2) return 1; @@ -138,7 +148,7 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B return 0; } - protected class SortedListCallBacks + private class SortedListCallBacks extends SortedList.Callback<ContactListItem> { @Override diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java index 1c2951b4006a0b6647a3b638cd9d2a26b996cbb3..63d978ff934b1517124e965805550c04029c29a8 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java @@ -68,11 +68,11 @@ public class ContactListAdapter extends BaseContactListAdapter.BaseContactHolder { public final ImageView bulb; - public final TextView unread; + final TextView unread; public final TextView date; public final TextView identity; - public ContactHolder(View v) { + ContactHolder(View v) { super(v); bulb = (ImageView) v.findViewById(R.id.bulbView); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index 7b21f28ac2950306b06673f50b64f200bd766971..d0514a17229dc5458b675b6eeb5172a8b3387f32 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -31,6 +31,7 @@ import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.MessageStateChangedEvent; +import org.briarproject.api.event.PrivateMessageReceivedEvent; import org.briarproject.api.forum.ForumInvitationMessage; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.IdentityManager; @@ -231,12 +232,16 @@ public class ContactListFragment extends BaseFragment implements EventListener { } else if (e instanceof ContactRemovedEvent) { LOG.info("Contact removed"); removeItem(((ContactRemovedEvent) e).getContactId()); + } else if (e instanceof PrivateMessageReceivedEvent) { + LOG.info("Message received, update contact"); + PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e; + PrivateMessageHeader h = p.getMessageHeader(); + updateItem(p.getGroupId(), ConversationItem.from(h)); } else if (e instanceof MessageStateChangedEvent) { MessageStateChangedEvent m = (MessageStateChangedEvent) e; ClientId c = m.getClientId(); if (m.getState() == DELIVERED && - (c.equals(messagingManager.getClientId()) || - c.equals(introductionManager.getClientId()) || + (c.equals(introductionManager.getClientId()) || c.equals(forumSharingManager.getClientId()))) { LOG.info("Message added, reloading"); reloadConversation(m.getMessage().getGroupId()); @@ -278,6 +283,20 @@ public class ContactListFragment extends BaseFragment implements EventListener { }); } + private void updateItem(final GroupId g, final ConversationItem m) { + listener.runOnUiThread(new Runnable() { + @Override + public void run() { + int position = adapter.findItemPosition(g); + ContactListItem item = adapter.getItem(position); + if (item != null) { + item.addMessage(m); + adapter.updateItem(position, item); + } + } + }); + } + private void removeItem(final ContactId c) { listener.runOnUiThread(new Runnable() { @Override diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItem.java b/briar-android/src/org/briarproject/android/contact/ContactListItem.java index ab43b1ed5979d4cd1d9c4f050e969b2ab59e6165..e436d4a9b230067ff294cffa28c823855dc97bb1 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListItem.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListItem.java @@ -35,13 +35,21 @@ public class ContactListItem { unread = 0; if (!empty) { for (ConversationItem i : messages) { - if (i.getTime() > timestamp) timestamp = i.getTime(); - if (i instanceof IncomingItem && !((IncomingItem) i).isRead()) - unread++; + addMessage(i); } } } + void addMessage(ConversationItem message) { + empty = empty && message == null; + if (message != null) { + if (message.getTime() > timestamp) timestamp = message.getTime(); + if (message instanceof IncomingItem && + !((IncomingItem) message).isRead()) + unread++; + } + } + public Contact getContact() { return contact; } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index f91d0644051705fffc3c8ce9e05f92de695e5d0a..d50adf35a5b08381363b645ebcfca8f93ac2f298 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -50,6 +50,7 @@ import org.briarproject.api.event.IntroductionResponseReceivedEvent; import org.briarproject.api.event.MessageStateChangedEvent; import org.briarproject.api.event.MessagesAckedEvent; import org.briarproject.api.event.MessagesSentEvent; +import org.briarproject.api.event.PrivateMessageReceivedEvent; import org.briarproject.api.forum.ForumInvitationMessage; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.introduction.IntroductionManager; @@ -416,7 +417,7 @@ public class ConversationActivity extends BriarActivity }); } - private void addIntroduction(final ConversationItem item) { + private void addConversationItem(final ConversationItem item) { runOnUiThread(new Runnable() { @Override public void run() { @@ -469,14 +470,23 @@ public class ConversationActivity extends BriarActivity LOG.info("Contact removed"); finishOnUiThread(); } + } else if (e instanceof PrivateMessageReceivedEvent) { + PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e; + if (p.getGroupId().equals(groupId)) { + LOG.info("Message received, adding"); + PrivateMessageHeader h = p.getMessageHeader(); + addConversationItem(ConversationItem.from(h)); + loadMessageBody(h); + markMessageReadIfNew(h); + } } else if (e instanceof MessageStateChangedEvent) { MessageStateChangedEvent m = (MessageStateChangedEvent) e; if (m.getState() == DELIVERED && m.getMessage().getGroupId().equals(groupId)) { - LOG.info("Message added, reloading"); - // Mark new incoming messages as read directly - if (m.isLocal()) loadMessages(); - else markMessageReadIfNew(m.getMessage()); + if (m.isLocal()) { + LOG.info("Message added, reloading"); + loadMessages(); + } } } else if (e instanceof MessagesSentEvent) { MessagesSentEvent m = (MessagesSentEvent) e; @@ -510,7 +520,7 @@ public class ConversationActivity extends BriarActivity if (event.getContactId().equals(contactId)) { IntroductionRequest ir = event.getIntroductionRequest(); ConversationItem item = new ConversationIntroductionInItem(ir); - addIntroduction(item); + addConversationItem(item); } } else if (e instanceof IntroductionResponseReceivedEvent) { IntroductionResponseReceivedEvent event = @@ -519,7 +529,7 @@ public class ConversationActivity extends BriarActivity IntroductionResponse ir = event.getIntroductionResponse(); ConversationItem item = ConversationItem.from(this, contactName, ir); - addIntroduction(item); + addConversationItem(item); } } else if (e instanceof ForumInvitationReceivedEvent) { ForumInvitationReceivedEvent event = @@ -530,7 +540,7 @@ public class ConversationActivity extends BriarActivity } } - private void markMessageReadIfNew(final Message m) { + private void markMessageReadIfNew(final PrivateMessageHeader h) { runOnUiThread(new Runnable() { @Override public void run() { @@ -538,23 +548,23 @@ public class ConversationActivity extends BriarActivity if (item != null) { // Mark the message read if it's the newest message long lastMsgTime = item.getTime(); - long newMsgTime = m.getTimestamp(); - if (newMsgTime > lastMsgTime) markNewMessageRead(m); + long newMsgTime = h.getTimestamp(); + if (newMsgTime > lastMsgTime) markNewMessageRead(h.getId()); else loadMessages(); } else { // mark the message as read as well if it is the first one - markNewMessageRead(m); + markNewMessageRead(h.getId()); } } }); } - private void markNewMessageRead(final Message m) { + private void markNewMessageRead(final MessageId m) { runOnDbThread(new Runnable() { @Override public void run() { try { - messagingManager.setReadFlag(m.getId(), true); + messagingManager.setReadFlag(m, true); loadMessages(); } catch (DbException e) { if (LOG.isLoggable(WARNING)) diff --git a/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..04f7f9164575eadc2021c2286676df01e32e87be --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java @@ -0,0 +1,27 @@ +package org.briarproject.api.event; + +import org.briarproject.api.messaging.PrivateMessageHeader; +import org.briarproject.api.sync.GroupId; + +/** + * An event that is broadcast when a new private message was received. + */ +public class PrivateMessageReceivedEvent extends Event { + + private final PrivateMessageHeader messageHeader; + private final GroupId groupId; + + public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader, + GroupId groupId) { + this.messageHeader = messageHeader; + this.groupId = groupId; + } + + public PrivateMessageHeader getMessageHeader() { + return messageHeader; + } + + public GroupId getGroupId() { + return groupId; + } +} diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java index 93a0cc979cfbab9f5296d95158555132d28c650d..052df83c3b0c0dcbee6b744cf6cbb505f5cd5b4d 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java @@ -10,17 +10,21 @@ import org.briarproject.api.contact.ContactManager.AddContactHook; import org.briarproject.api.contact.ContactManager.RemoveContactHook; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataParser; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; import org.briarproject.api.db.Transaction; +import org.briarproject.api.event.PrivateMessageReceivedEvent; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessage; import org.briarproject.api.messaging.PrivateMessageHeader; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageStatus; +import org.briarproject.clients.BdfIncomingMessageHook; import org.briarproject.util.StringUtils; import java.util.ArrayList; @@ -29,22 +33,23 @@ import java.util.Map; import javax.inject.Inject; -class MessagingManagerImpl implements MessagingManager, Client, AddContactHook, - RemoveContactHook { +class MessagingManagerImpl extends BdfIncomingMessageHook + implements MessagingManager, Client, AddContactHook, RemoveContactHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( "6bcdc006c0910b0f44e40644c3b31f1a" + "8bf9a6d6021d40d219c86b731b903070")); private final DatabaseComponent db; - private final ClientHelper clientHelper; private final PrivateGroupFactory privateGroupFactory; @Inject MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper, + MetadataParser metadataParser, PrivateGroupFactory privateGroupFactory) { + super(clientHelper, metadataParser); + this.db = db; - this.clientHelper = clientHelper; this.privateGroupFactory = privateGroupFactory; } @@ -87,6 +92,22 @@ class MessagingManagerImpl implements MessagingManager, Client, AddContactHook, return CLIENT_ID; } + @Override + protected void incomingMessage(Transaction txn, Message m, BdfList body, + BdfDictionary meta) throws DbException, FormatException { + + GroupId groupId = m.getGroupId(); + long timestamp = meta.getLong("timestamp"); + String contentType = meta.getString("contentType"); + boolean local = meta.getBoolean("local"); + boolean read = meta.getBoolean("read"); + PrivateMessageHeader header = new PrivateMessageHeader( + m.getId(), timestamp, contentType, local, read, false, false); + PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent( + header, groupId); + txn.attach(event); + } + @Override public void addLocalMessage(PrivateMessage m) throws DbException { try { diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java index 8fec2d9b6c10b24a9adc0c6398d27555a3a59324..d22782cf42b7f19d87c954721a3c0524759e160b 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingModule.java +++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java @@ -45,11 +45,13 @@ public class MessagingModule { @Provides @Singleton MessagingManager getMessagingManager(LifecycleManager lifecycleManager, - ContactManager contactManager, + ContactManager contactManager, ValidationManager validationManager, MessagingManagerImpl messagingManager) { lifecycleManager.registerClient(messagingManager); contactManager.registerAddContactHook(messagingManager); contactManager.registerRemoveContactHook(messagingManager); + validationManager + .registerIncomingMessageHook(CLIENT_ID, messagingManager); return messagingManager; } }