diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java index e0a7ada60e1cfede6ca822e31135517d30531b04..5515094fb97cb88a6519fbe1757d864149c347b0 100644 --- a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java @@ -17,6 +17,7 @@ import org.briarproject.event.EventModule; import org.briarproject.forum.ForumModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.messaging.MessagingModule; import org.briarproject.properties.PropertiesModule; import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; @@ -46,7 +47,8 @@ import dagger.Component; SharingModule.class, SyncModule.class, SystemModule.class, - TransportModule.class + TransportModule.class, + MessagingModule.class }) interface BlogSharingIntegrationTestComponent { diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java index 74c771488f832a608ebf66ee610a0e5fd6e1ddc2..fee35a0088438d7d5d04547f210002e58c3de28f 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java @@ -17,6 +17,7 @@ import org.briarproject.event.EventModule; import org.briarproject.forum.ForumModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.messaging.MessagingModule; import org.briarproject.properties.PropertiesModule; import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; @@ -46,7 +47,8 @@ import dagger.Component; SharingModule.class, SyncModule.class, SystemModule.class, - TransportModule.class + TransportModule.class, + MessagingModule.class }) interface ForumManagerTestComponent { diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java index 10dacd7c8041ea2a6ccd03987ccaaf4ad59a2fad..88b058807ce19031ffa8f311ffb8c42c2cd55708 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java @@ -21,6 +21,7 @@ import org.briarproject.event.EventModule; import org.briarproject.forum.ForumModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.messaging.MessagingModule; import org.briarproject.properties.PropertiesModule; import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; @@ -50,7 +51,8 @@ import dagger.Component; SharingModule.class, SyncModule.class, SystemModule.class, - TransportModule.class + TransportModule.class, + MessagingModule.class }) interface ForumSharingIntegrationTestComponent { diff --git a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTestComponent.java index c1f7077a497fa2d7c51269cda0ec504e15a75ebe..617fa1cee530f83f0125018fdda60e0ac80c71fe 100644 --- a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTestComponent.java @@ -20,6 +20,7 @@ import org.briarproject.db.DatabaseModule; import org.briarproject.event.EventModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.messaging.MessagingModule; import org.briarproject.properties.PropertiesModule; import org.briarproject.sync.SyncModule; import org.briarproject.system.SystemModule; @@ -46,7 +47,8 @@ import dagger.Component; SyncModule.class, SystemModule.class, DataModule.class, - PropertiesModule.class + PropertiesModule.class, + MessagingModule.class }) public interface IntroductionIntegrationTestComponent { diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java index a5880d33686c970c759ea1f33008fd34e2c9b39d..ce051f5349f136428e6921607bca39516f24abe4 100644 --- a/briar-android/src/org/briarproject/android/AndroidComponent.java +++ b/briar-android/src/org/briarproject/android/AndroidComponent.java @@ -30,6 +30,7 @@ import org.briarproject.api.keyagreement.PayloadEncoder; import org.briarproject.api.keyagreement.PayloadParser; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.plugins.ConnectionRegistry; @@ -86,6 +87,8 @@ public interface AndroidComponent extends CoreEagerSingletons { ContactManager contactManager(); + ConversationManager conversationManager(); + MessagingManager messagingManager(); PrivateMessageFactory privateMessageFactory(); diff --git a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java index 966de01db949176bda374f03248e51174c1c0b88..7d47079e137bde40a5db8c649291f78938910286 100644 --- a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java +++ b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java @@ -28,7 +28,7 @@ import org.briarproject.api.event.ForumPostReceivedEvent; import org.briarproject.api.event.IntroductionRequestReceivedEvent; import org.briarproject.api.event.IntroductionResponseReceivedEvent; import org.briarproject.api.event.IntroductionSucceededEvent; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.event.PrivateMessageReceivedEvent; import org.briarproject.api.event.SettingsUpdatedEvent; @@ -235,8 +235,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager, } else if (e instanceof IntroductionResponseReceivedEvent) { ContactId c = ((IntroductionResponseReceivedEvent) e).getContactId(); showNotificationForPrivateConversation(c); - } else if (e instanceof InvitationReceivedEvent) { - ContactId c = ((InvitationReceivedEvent) e).getContactId(); + } else if (e instanceof InvitationRequestReceivedEvent) { + ContactId c = ((InvitationRequestReceivedEvent) e).getContactId(); showNotificationForPrivateConversation(c); } else if (e instanceof InvitationResponseReceivedEvent) { ContactId c = ((InvitationResponseReceivedEvent) e).getContactId(); diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java index b1ab777c442989c4735d3b2d210729d4482ba065..aa48714f77f086e031054e7d5929e5b70c11ed24 100644 --- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java @@ -50,10 +50,8 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B } }); - if (item.getGroupId() != null) { - ViewCompat.setTransitionName(ui.avatar, "avatar" + - StringUtils.toHexString(item.getGroupId().getBytes())); - } + ViewCompat.setTransitionName(ui.avatar, "avatar" + + StringUtils.toHexString(item.getGroupId().getBytes())); } @Override @@ -96,8 +94,9 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B int count = getItemCount(); for (int i = 0; i < count; i++) { ContactListItem item = getItemAt(i); - if (item != null && item.getGroupId().equals(g)) + if (item != null && item.getGroupId().equals(g)) { return i; + } } return INVALID_POSITION; // Not found } diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index 5feb4d3a15a3014145aec79ac0d0e033e77770b1..22f77a841dc18a44aadf1c5772718188d4159b95 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -21,13 +21,12 @@ import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.keyagreement.KeyAgreementActivity; import org.briarproject.android.view.BriarRecyclerView; -import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.db.DbException; import org.briarproject.api.db.NoSuchContactException; -import org.briarproject.api.event.ContactAddedEvent; import org.briarproject.api.event.ContactConnectedEvent; import org.briarproject.api.event.ContactDisconnectedEvent; import org.briarproject.api.event.ContactRemovedEvent; @@ -37,24 +36,21 @@ import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.IntroductionRequestReceivedEvent; import org.briarproject.api.event.IntroductionResponseReceivedEvent; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.event.PrivateMessageReceivedEvent; -import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; -import org.briarproject.api.introduction.IntroductionManager; -import org.briarproject.api.introduction.IntroductionMessage; import org.briarproject.api.introduction.IntroductionRequest; import org.briarproject.api.introduction.IntroductionResponse; -import org.briarproject.api.messaging.MessagingManager; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.messaging.PrivateMessageHeader; import org.briarproject.api.plugins.ConnectionRegistry; -import org.briarproject.api.sharing.InvitationMessage; +import org.briarproject.api.sharing.InvitationRequest; +import org.briarproject.api.sharing.InvitationResponse; import org.briarproject.api.sync.GroupId; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.logging.Logger; @@ -88,13 +84,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { @Inject protected volatile IdentityManager identityManager; @Inject - protected volatile MessagingManager messagingManager; - @Inject - protected volatile IntroductionManager introductionManager; - @Inject - protected volatile ForumSharingManager forumSharingManager; - @Inject - protected volatile BlogSharingManager blogSharingManager; + protected volatile ConversationManager conversationManager; public static ContactListFragment newInstance() { @@ -130,7 +120,6 @@ public class ContactListFragment extends BaseFragment implements EventListener { new ContactListAdapter.OnItemClickListener() { @Override public void onItemClick(View view, ContactListItem item) { - GroupId groupId = item.getGroupId(); Intent i = new Intent(getActivity(), ConversationActivity.class); @@ -215,15 +204,15 @@ public class ContactListFragment extends BaseFragment implements EventListener { try { ContactId id = c.getId(); GroupId groupId = - messagingManager.getConversationId(id); - Collection<ConversationItem> messages = - getMessages(id); + conversationManager.getConversationId(id); + GroupCount count = + conversationManager.getGroupCount(id); boolean connected = connectionRegistry.isConnected(c.getId()); LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); contacts.add(new ContactListItem(c, localAuthor, - connected, groupId, messages)); + connected, groupId, count)); } catch (NoSuchContactException e) { // Continue } @@ -252,14 +241,9 @@ public class ContactListFragment extends BaseFragment implements EventListener { @Override public void eventOccurred(Event e) { - if (e instanceof ContactAddedEvent) { - if (((ContactAddedEvent) e).isActive()) { - LOG.info("Contact added as active, reloading"); - loadContacts(); - } - } else if (e instanceof ContactStatusChangedEvent) { + if (e instanceof ContactStatusChangedEvent) { LOG.info("Contact Status changed, reloading"); - // TODO We can update the contact state without needing to reload + // is also broadcast when contact was added loadContacts(); } else if (e instanceof ContactConnectedEvent) { setConnected(((ContactConnectedEvent) e).getContactId(), true); @@ -285,50 +269,20 @@ public class ContactListFragment extends BaseFragment implements EventListener { (IntroductionResponseReceivedEvent) e; IntroductionResponse ir = m.getIntroductionResponse(); updateItem(m.getContactId(), ConversationItem.from(ir)); - } else if (e instanceof InvitationReceivedEvent) { - LOG.info("Invitation received, reloading conversation..."); - InvitationReceivedEvent m = (InvitationReceivedEvent) e; - reloadConversation(m.getContactId()); + } else if (e instanceof InvitationRequestReceivedEvent) { + LOG.info("Invitation Request received, update contact"); + InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e; + InvitationRequest ir = m.getRequest(); + updateItem(m.getContactId(), ConversationItem.from(ir)); } else if (e instanceof InvitationResponseReceivedEvent) { - LOG.info("Invitation Response received, reloading ..."); + LOG.info("Invitation Response received, update contact"); InvitationResponseReceivedEvent m = (InvitationResponseReceivedEvent) e; - reloadConversation(m.getContactId()); + InvitationResponse ir = m.getResponse(); + updateItem(m.getContactId(), ConversationItem.from(ir)); } } - private void reloadConversation(final ContactId c) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - Collection<ConversationItem> messages = getMessages(c); - updateItem(c, messages); - } catch (NoSuchContactException e) { - LOG.info("Contact removed"); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); - } - - private void updateItem(final ContactId c, - final Collection<ConversationItem> messages) { - listener.runOnUiThread(new Runnable() { - @Override - public void run() { - int position = adapter.findItemPosition(c); - ContactListItem item = adapter.getItemAt(position); - if (item != null) { - item.setMessages(messages); - adapter.updateItemAt(position, item); - } - } - }); - } - private void updateItem(final ContactId c, final ConversationItem m) { listener.runOnUiThread(new Runnable() { @Override @@ -382,50 +336,4 @@ public class ContactListFragment extends BaseFragment implements EventListener { }); } - // This needs to be called from the DB thread - // Do not call getActivty() here as it might return null - private Collection<ConversationItem> getMessages(ContactId id) - throws DbException { - - long now = System.currentTimeMillis(); - - Collection<ConversationItem> messages = new ArrayList<>(); - - Collection<PrivateMessageHeader> headers = - messagingManager.getMessageHeaders(id); - for (PrivateMessageHeader h : headers) { - messages.add(ConversationItem.from(h)); - } - long duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Loading message headers took " + duration + " ms"); - - now = System.currentTimeMillis(); - Collection<IntroductionMessage> introductions = - introductionManager - .getIntroductionMessages(id); - for (IntroductionMessage m : introductions) { - messages.add(ConversationItem.from(m)); - } - duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Loading introduction messages took " + duration + " ms"); - - now = System.currentTimeMillis(); - Collection<InvitationMessage> forumInvitations = - forumSharingManager.getInvitationMessages(id); - for (InvitationMessage i : forumInvitations) { - messages.add(ConversationItem.from(i)); - } - Collection<InvitationMessage> blogInvitations = - blogSharingManager.getInvitationMessages(id); - for (InvitationMessage i : blogInvitations) { - messages.add(ConversationItem.from(i)); - } - duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Loading invitations took " + duration + " ms"); - - return messages; - } } diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItem.java b/briar-android/src/org/briarproject/android/contact/ContactListItem.java index e436d4a9b230067ff294cffa28c823855dc97bb1..e90cdf939b14f6a582594bcc36dd36d4b2aa7909 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListItem.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListItem.java @@ -1,14 +1,14 @@ package org.briarproject.android.contact; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.GroupId; - -import java.util.Collection; +import org.jetbrains.annotations.NotNull; import static org.briarproject.android.contact.ConversationItem.IncomingItem; -// This class is not thread-safe +// This class is NOT thread-safe public class ContactListItem { private final Contact contact; @@ -18,26 +18,16 @@ public class ContactListItem { private long timestamp; private int unread; - public ContactListItem(Contact contact, LocalAuthor localAuthor, - boolean connected, - GroupId groupId, - Collection<ConversationItem> messages) { + public ContactListItem(@NotNull Contact contact, + @NotNull LocalAuthor localAuthor, boolean connected, + @NotNull GroupId groupId, @NotNull GroupCount count) { this.contact = contact; this.localAuthor = localAuthor; this.groupId = groupId; this.connected = connected; - setMessages(messages); - } - - void setMessages(Collection<ConversationItem> messages) { - empty = messages == null || messages.isEmpty(); - timestamp = 0; - unread = 0; - if (!empty) { - for (ConversationItem i : messages) { - addMessage(i); - } - } + this.empty = count.getMsgCount() == 0; + this.unread = count.getUnreadCount(); + this.timestamp = count.getLatestMsgTime(); } void addMessage(ConversationItem message) { diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index 6f3f1f4e894eb470fb2cd70c80dad556932d8bc2..75c0b88c8fc38fda8a0b4bda51de840049608bf8 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -34,6 +34,7 @@ import org.briarproject.android.view.TextInputView; import org.briarproject.android.view.TextInputView.TextInputListener; import org.briarproject.api.FormatException; import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.clients.BaseMessageHeader; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -50,7 +51,7 @@ import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.IntroductionRequestReceivedEvent; import org.briarproject.api.event.IntroductionResponseReceivedEvent; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.event.MessagesAckedEvent; import org.briarproject.api.event.MessagesSentEvent; @@ -76,7 +77,7 @@ import org.briarproject.util.StringUtils; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -476,28 +477,28 @@ public class ConversationActivity extends BriarActivity } private void markMessagesRead() { - List<MessageId> unread = new ArrayList<>(); + Map<MessageId, GroupId> unread = new HashMap<>(); SparseArray<IncomingItem> list = adapter.getIncomingMessages(); for (int i = 0; i < list.size(); i++) { IncomingItem item = list.valueAt(i); - if (!item.isRead()) unread.add(item.getId()); + if (!item.isRead()) + unread.put(item.getId(), item.getGroupId()); } if (unread.isEmpty()) return; if (LOG.isLoggable(INFO)) LOG.info("Marking " + unread.size() + " messages read"); - markMessagesRead(Collections.unmodifiableList(unread)); + markMessagesRead(unread); } - private void markMessagesRead(final Collection<MessageId> unread) { + private void markMessagesRead(final Map<MessageId, GroupId> unread) { runOnDbThread(new Runnable() { @Override public void run() { try { long now = System.currentTimeMillis(); - for (MessageId m : unread) - // not really clean, but the messaging manager can - // handle introduction messages as well - messagingManager.setReadFlag(groupId, m, true); + for (Map.Entry<MessageId, GroupId> e : unread.entrySet()) + messagingManager + .setReadFlag(e.getValue(), e.getKey(), true); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Marking read took " + duration + " ms"); @@ -560,6 +561,7 @@ public class ConversationActivity extends BriarActivity IntroductionRequest ir = event.getIntroductionRequest(); ConversationItem item = new ConversationIntroductionInItem(ir); addConversationItem(item); + markMessageReadIfNew(ir); } } else if (e instanceof IntroductionResponseReceivedEvent) { IntroductionResponseReceivedEvent event = @@ -570,25 +572,33 @@ public class ConversationActivity extends BriarActivity ConversationItem item = ConversationItem.from(this, contactName, ir); addConversationItem(item); + markMessageReadIfNew(ir); } - } else if (e instanceof InvitationReceivedEvent) { - InvitationReceivedEvent event = - (InvitationReceivedEvent) e; + } else if (e instanceof InvitationRequestReceivedEvent) { + InvitationRequestReceivedEvent event = + (InvitationRequestReceivedEvent) e; if (event.getContactId().equals(contactId)) { - LOG.info("Invitation received, reloading..."); - loadMessages(); + LOG.info("Invitation received, adding..."); + InvitationRequest ir = event.getRequest(); + ConversationItem item = ConversationItem.from(ir); + addConversationItem(item); + markMessageReadIfNew(ir); } } else if (e instanceof InvitationResponseReceivedEvent) { InvitationResponseReceivedEvent event = (InvitationResponseReceivedEvent) e; if (event.getContactId().equals(contactId)) { - LOG.info("Invitation response received, reloading..."); - loadMessages(); + LOG.info("Invitation response received, adding..."); + InvitationResponse ir = event.getResponse(); + ConversationItem item = + ConversationItem.from(this, contactName, ir); + addConversationItem(item); + markMessageReadIfNew(ir); } } } - private void markMessageReadIfNew(final PrivateMessageHeader h) { + private void markMessageReadIfNew(final BaseMessageHeader h) { runOnUiThread(new Runnable() { @Override public void run() { @@ -597,22 +607,23 @@ public class ConversationActivity extends BriarActivity // Mark the message read if it's the newest message long lastMsgTime = item.getTime(); long newMsgTime = h.getTimestamp(); - if (newMsgTime > lastMsgTime) markNewMessageRead(h.getId()); + if (newMsgTime > lastMsgTime) + markNewMessageRead(h.getGroupId(), h.getId()); else loadMessages(); } else { // mark the message as read as well if it is the first one - markNewMessageRead(h.getId()); + markNewMessageRead(h.getGroupId(), h.getId()); } } }); } - private void markNewMessageRead(final MessageId m) { + private void markNewMessageRead(final GroupId g, final MessageId m) { runOnDbThread(new Runnable() { @Override public void run() { try { - messagingManager.setReadFlag(groupId, m, true); + messagingManager.setReadFlag(g, m, true); loadMessages(); } catch (DbException e) { if (LOG.isLoggable(WARNING)) @@ -681,11 +692,10 @@ public class ConversationActivity extends BriarActivity long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Storing message took " + duration + " ms"); - MessageId id = m.getMessage().getId(); PrivateMessageHeader h = new PrivateMessageHeader(id, - m.getMessage().getTimestamp(), m.getContentType(), - true, false, false, false); + groupId, m.getMessage().getTimestamp(), + m.getContentType(), true, false, false, false); ConversationMessageItem item = ConversationItem.from(h); item.setBody(body); bodyCache.put(id, body); diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java index 331a062358c62d4c6d5fef55771e6259cda7ac0f..6959d214b10abb5599c5d1e04d439ecc7ae1f296 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java @@ -1,14 +1,16 @@ package org.briarproject.android.contact; +import org.briarproject.android.contact.ConversationItem.IncomingItem; import org.briarproject.api.introduction.IntroductionRequest; +import org.jetbrains.annotations.NotNull; // This class is not thread-safe class ConversationIntroductionInItem extends ConversationIntroductionItem - implements ConversationItem.IncomingItem { + implements IncomingItem { private boolean read; - ConversationIntroductionInItem(IntroductionRequest ir) { + ConversationIntroductionInItem(@NotNull IntroductionRequest ir) { super(ir); this.read = ir.isRead(); diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java index 5fb30a23d96611efffbaa7ba13541082109e8483..d2cdef596ffdadd4c4b38a280f5536ce0d4ead6a 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java @@ -1,6 +1,7 @@ package org.briarproject.android.contact; import org.briarproject.api.introduction.IntroductionRequest; +import org.jetbrains.annotations.NotNull; // This class is not thread-safe abstract class ConversationIntroductionItem extends ConversationItem { @@ -8,13 +9,14 @@ abstract class ConversationIntroductionItem extends ConversationItem { private final IntroductionRequest ir; private boolean answered; - ConversationIntroductionItem(IntroductionRequest ir) { - super(ir.getMessageId(), ir.getTimestamp()); + ConversationIntroductionItem(@NotNull IntroductionRequest ir) { + super(ir.getMessageId(), ir.getGroupId(), ir.getTimestamp()); this.ir = ir; this.answered = ir.wasAnswered(); } + @NotNull IntroductionRequest getIntroductionRequest() { return ir; } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationItem.java b/briar-android/src/org/briarproject/android/contact/ConversationItem.java index 083dc6bf7840ce47c8611d729e2ec5de1dc583dd..d8c5e5aa746900f212744ae1423f811e5e09f818 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationItem.java @@ -12,7 +12,9 @@ import org.briarproject.api.messaging.PrivateMessageHeader; import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sharing.InvitationRequest; import org.briarproject.api.sharing.InvitationResponse; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; // This class is not thread-safe public abstract class ConversationItem { @@ -30,20 +32,29 @@ public abstract class ConversationItem { final static int BLOG_INVITATION_IN = 9; final static int BLOG_INVITATION_OUT = 10; - private MessageId id; - private long time; + final private MessageId id; + final private GroupId groupId; + final private long time; - public ConversationItem(MessageId id, long time) { + public ConversationItem(@NotNull MessageId id, @NotNull GroupId groupId, + long time) { this.id = id; + this.groupId = groupId; this.time = time; } abstract int getType(); + @NotNull public MessageId getId() { return id; } + @NotNull + public GroupId getGroupId() { + return groupId; + } + long getTime() { return time; } @@ -78,8 +89,9 @@ public abstract class ConversationItem { R.string.introduction_response_declined_sent, ir.getName()); } - return new ConversationNoticeOutItem(ir.getMessageId(), text, - ir.getTimestamp(), ir.isSent(), ir.isSeen()); + return new ConversationNoticeOutItem(ir.getMessageId(), + ir.getGroupId(), text, ir.getTimestamp(), ir.isSent(), + ir.isSeen()); } else { String text; if (ir.wasAccepted()) { @@ -97,8 +109,8 @@ public abstract class ConversationItem { contactName, ir.getName()); } } - return new ConversationNoticeInItem(ir.getMessageId(), text, - ir.getTimestamp(), ir.isRead()); + return new ConversationNoticeInItem(ir.getMessageId(), + ir.getGroupId(), text, ir.getTimestamp(), ir.isRead()); } } @@ -137,8 +149,8 @@ public abstract class ConversationItem { R.string.forum_invitation_response_declined_sent, contactName); } - return new ConversationNoticeOutItem(fir.getId(), text, - fir.getTimestamp(), fir.isSent(), fir.isSeen()); + return new ConversationNoticeOutItem(fir.getId(), fir.getGroupId(), + text, fir.getTimestamp(), fir.isSent(), fir.isSeen()); } else { String text; if (fir.wasAccepted()) { @@ -150,8 +162,8 @@ public abstract class ConversationItem { R.string.forum_invitation_response_declined_received, contactName); } - return new ConversationNoticeInItem(fir.getId(), text, - fir.getTimestamp(), fir.isRead()); + return new ConversationNoticeInItem(fir.getId(), fir.getGroupId(), + text, fir.getTimestamp(), fir.isRead()); } } @@ -169,8 +181,8 @@ public abstract class ConversationItem { R.string.blogs_sharing_response_declined_sent, contactName); } - return new ConversationNoticeOutItem(fir.getId(), text, - fir.getTimestamp(), fir.isSent(), fir.isSeen()); + return new ConversationNoticeOutItem(fir.getId(), fir.getGroupId(), + text, fir.getTimestamp(), fir.isSent(), fir.isSeen()); } else { String text; if (fir.wasAccepted()) { @@ -182,8 +194,8 @@ public abstract class ConversationItem { R.string.blogs_sharing_response_declined_received, contactName); } - return new ConversationNoticeInItem(fir.getId(), text, - fir.getTimestamp(), fir.isRead()); + return new ConversationNoticeInItem(fir.getId(), fir.getGroupId(), + text, fir.getTimestamp(), fir.isRead()); } } @@ -193,10 +205,10 @@ public abstract class ConversationItem { */ public static ConversationItem from(IntroductionMessage im) { if (im.isLocal()) - return new ConversationNoticeOutItem(im.getMessageId(), "", - im.getTimestamp(), false, false); - return new ConversationNoticeInItem(im.getMessageId(), "", - im.getTimestamp(), im.isRead()); + return new ConversationNoticeOutItem(im.getMessageId(), + im.getGroupId(), "", im.getTimestamp(), false, false); + return new ConversationNoticeInItem(im.getMessageId(), im.getGroupId(), + "", im.getTimestamp(), im.isRead()); } /** @@ -205,14 +217,15 @@ public abstract class ConversationItem { */ public static ConversationItem from(InvitationMessage im) { if (im.isLocal()) - return new ConversationNoticeOutItem(im.getId(), "", - im.getTimestamp(), false, false); - return new ConversationNoticeInItem(im.getId(), "", + return new ConversationNoticeOutItem(im.getId(), im.getGroupId(), + "", im.getTimestamp(), false, false); + return new ConversationNoticeInItem(im.getId(), im.getGroupId(), "", im.getTimestamp(), im.isRead()); } interface OutgoingItem { + @NotNull MessageId getId(); boolean isSent(); @@ -226,8 +239,12 @@ public abstract class ConversationItem { interface IncomingItem { + @NotNull MessageId getId(); + @NotNull + GroupId getGroupId(); + boolean isRead(); void setRead(boolean read); diff --git a/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java b/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java index b7a6aac44a9b35698ae9a5a59c744be1b46d0034..b4dc64b6cc8c2aa86e729f545b19a7a78776b04d 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java @@ -9,7 +9,7 @@ abstract class ConversationMessageItem extends ConversationItem { private byte[] body; ConversationMessageItem(PrivateMessageHeader header) { - super(header.getId(), header.getTimestamp()); + super(header.getId(), header.getGroupId(), header.getTimestamp()); this.header = header; body = null; diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java index bfa83160b167cac8761a3cde87a59fc195cfdde5..6e8fbfc8bcb3331b817bea7793f3295eb30b1cfa 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java @@ -1,5 +1,6 @@ package org.briarproject.android.contact; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; // This class is not thread-safe @@ -8,9 +9,9 @@ class ConversationNoticeInItem extends ConversationNoticeItem private boolean read; - ConversationNoticeInItem(MessageId id, String text, long time, - boolean read) { - super(id, text, time); + ConversationNoticeInItem(MessageId id, GroupId groupId, String text, + long time, boolean read) { + super(id, groupId, text, time); this.read = read; } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java index b722ab95d2c32c945e544dcda0d10c5e95e8472f..758c311d01f57e9611e1a5b7411c7dcc41d4d689 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java @@ -1,13 +1,15 @@ package org.briarproject.android.contact; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; abstract class ConversationNoticeItem extends ConversationItem { private final String text; - ConversationNoticeItem(MessageId id, String text, long time) { - super(id, time); + ConversationNoticeItem(MessageId id, GroupId groupId, String text, + long time) { + super(id, groupId, time); this.text = text; } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java index a5bdb5e20bf1fc2255c3c27214d3ecabd80fe329..95ed78510fba0d585b51044422d660a0f1d3a7ad 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java @@ -1,5 +1,6 @@ package org.briarproject.android.contact; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; // This class is not thread-safe @@ -8,9 +9,9 @@ class ConversationNoticeOutItem extends ConversationNoticeItem private boolean sent, seen; - ConversationNoticeOutItem(MessageId id, String text, long time, - boolean sent, boolean seen) { - super(id, text, time); + ConversationNoticeOutItem(MessageId id, GroupId groupId, String text, + long time, boolean sent, boolean seen) { + super(id, groupId, text, time); this.sent = sent; this.seen = seen; diff --git a/briar-android/src/org/briarproject/android/contact/ConversationShareableInvitationItem.java b/briar-android/src/org/briarproject/android/contact/ConversationShareableInvitationItem.java index a2e9b91cf06166a1c626e8b3de00cdb5e4e345f3..60f8a70b1ca4bd1f331925cb771c35813e1f422e 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationShareableInvitationItem.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationShareableInvitationItem.java @@ -7,7 +7,7 @@ abstract class ConversationShareableInvitationItem extends ConversationItem { private final InvitationRequest fim; ConversationShareableInvitationItem(InvitationRequest fim) { - super(fim.getId(), fim.getTimestamp()); + super(fim.getId(), fim.getGroupId(), fim.getTimestamp()); this.fim = fim; } diff --git a/briar-android/src/org/briarproject/android/forum/ForumItem.java b/briar-android/src/org/briarproject/android/forum/ForumItem.java deleted file mode 100644 index 92ae9320bf7ec48eeeb6b77c6a00ce51bc17ab76..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/forum/ForumItem.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.briarproject.android.forum; - -import org.briarproject.api.forum.ForumPostHeader; - -// This class is not thread-safe -class ForumItem { - - private final ForumPostHeader header; - private byte[] body; - - ForumItem(ForumPostHeader header) { - this.header = header; - body = null; - } - - ForumPostHeader getHeader() { - return header; - } - - byte[] getBody() { - return body; - } - - void setBody(byte[] body) { - this.body = body; - } -} diff --git a/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java b/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java deleted file mode 100644 index d482b979b7d8e95caec1c15c61ce9c89d5f77693..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.briarproject.android.forum; - -import java.util.Comparator; - -class ForumItemComparator implements Comparator<ForumItem> { - - static final ForumItemComparator INSTANCE = new ForumItemComparator(); - - public int compare(ForumItem a, ForumItem b) { - // The oldest message comes first - long aTime = a.getHeader().getTimestamp(); - long bTime = b.getHeader().getTimestamp(); - if (aTime < bTime) return -1; - if (aTime > bTime) return 1; - return 0; - } -} diff --git a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java index 9c3ba15fe3d578a3c5269ae79999678bfdf95fda..ca237eb35e8847002c3aec56dd3894a0cd285911 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java @@ -17,6 +17,7 @@ import org.briarproject.android.view.TextAvatarView; import org.briarproject.api.forum.Forum; import org.briarproject.api.sync.GroupId; +import static android.support.v7.util.SortedList.INVALID_POSITION; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static org.briarproject.android.BriarActivity.GROUP_ID; @@ -104,7 +105,7 @@ class ForumListAdapter @Override public boolean areContentsTheSame(ForumListItem a, ForumListItem b) { - return a.getForum().equals(b.getForum()) && + return a.isEmpty() == b.isEmpty() && a.getTimestamp() == b.getTimestamp() && a.getUnreadCount() == b.getUnreadCount(); } @@ -125,10 +126,14 @@ class ForumListAdapter return null; } - void updateItem(ForumListItem item) { - ForumListItem oldItem = findItem(item.getForum().getGroup().getId()); - int position = items.indexOf(oldItem); - items.updateItemAt(position, item); + int findItemPosition(GroupId g) { + int count = getItemCount(); + for (int i = 0; i < count; i++) { + ForumListItem item = getItemAt(i); + if (item != null && item.getForum().getGroup().getId().equals(g)) + return i; + } + return INVALID_POSITION; // Not found } static class ForumViewHolder extends RecyclerView.ViewHolder { diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index 94f2e2e4e322b956f9b9a228e7e76059c3a1c401..70d82d05d974105f3ac5ba301f7fcf620727f19e 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -20,6 +20,7 @@ import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.fragment.BaseEventFragment; import org.briarproject.android.sharing.InvitationsForumActivity; import org.briarproject.android.view.BriarRecyclerView; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.db.DbException; import org.briarproject.api.db.NoSuchGroupException; import org.briarproject.api.event.ContactRemovedEvent; @@ -47,11 +48,8 @@ import static java.util.logging.Level.WARNING; public class ForumListFragment extends BaseEventFragment implements OnClickListener { - public final static String TAG = "ForumListFragment"; - - private static final Logger LOG = - Logger.getLogger(ForumListFragment.class.getName()); - + public final static String TAG = ForumListFragment.class.getName(); + private final static Logger LOG = Logger.getLogger(TAG); private BriarRecyclerView list; private ForumListAdapter adapter; @@ -118,7 +116,7 @@ public class ForumListFragment extends BaseEventFragment implements notificationManager.blockAllForumPostNotifications(); notificationManager.clearAllForumPostNotifications(); - loadForumHeaders(); + loadForums(); loadAvailableForums(); list.startPeriodicUpdate(); } @@ -153,7 +151,7 @@ public class ForumListFragment extends BaseEventFragment implements } } - private void loadForumHeaders() { + private void loadForums() { listener.runOnDbThread(new Runnable() { @Override public void run() { @@ -163,14 +161,14 @@ public class ForumListFragment extends BaseEventFragment implements Collection<ForumListItem> forums = new ArrayList<>(); for (Forum f : forumManager.getForums()) { try { - Collection<ForumPostHeader> headers = - forumManager.getPostHeaders(f.getId()); - forums.add(new ForumListItem(f, headers)); + GroupCount count = + forumManager.getGroupCount(f.getId()); + forums.add(new ForumListItem(f, count)); } catch (NoSuchGroupException e) { // Continue } } - displayForumHeaders(forums); + displayForums(forums); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Full load took " + duration + " ms"); @@ -182,7 +180,7 @@ public class ForumListFragment extends BaseEventFragment implements }); } - private void displayForumHeaders(final Collection<ForumListItem> forums) { + private void displayForums(final Collection<ForumListItem> forums) { listener.runOnUiThread(new Runnable() { @Override public void run() { @@ -238,7 +236,7 @@ public class ForumListFragment extends BaseEventFragment implements GroupAddedEvent g = (GroupAddedEvent) e; if (g.getGroup().getClientId().equals(forumManager.getClientId())) { LOG.info("Forum added, reloading forums"); - loadForumHeaders(); + loadForums(); } } else if (e instanceof GroupRemovedEvent) { GroupRemovedEvent g = (GroupRemovedEvent) e; @@ -248,39 +246,23 @@ public class ForumListFragment extends BaseEventFragment implements } } else if (e instanceof ForumPostReceivedEvent) { ForumPostReceivedEvent m = (ForumPostReceivedEvent) e; - LOG.info("Forum post added, reloading"); - loadForumHeaders(m.getGroupId()); + LOG.info("Forum post added, updating..."); + updateItem(m.getGroupId(), m.getForumPostHeader()); } else if (e instanceof ForumInvitationReceivedEvent) { loadAvailableForums(); } } - private void loadForumHeaders(final GroupId g) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - long now = System.currentTimeMillis(); - Forum f = forumManager.getForum(g); - Collection<ForumPostHeader> headers = - forumManager.getPostHeaders(g); - long duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Partial load took " + duration + " ms"); - updateForum(new ForumListItem(f, headers)); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); - } - - private void updateForum(final ForumListItem item) { + private void updateItem(final GroupId g, final ForumPostHeader m) { listener.runOnUiThread(new Runnable() { @Override public void run() { - adapter.updateItem(item); + int position = adapter.findItemPosition(g); + ForumListItem item = adapter.getItemAt(position); + if (item != null) { + item.addHeader(m); + adapter.updateItemAt(position, item); + } } }); } @@ -289,7 +271,8 @@ public class ForumListFragment extends BaseEventFragment implements listener.runOnUiThread(new Runnable() { @Override public void run() { - ForumListItem item = adapter.findItem(g); + int position = adapter.findItemPosition(g); + ForumListItem item = adapter.getItemAt(position); if (item != null) adapter.remove(item); } }); diff --git a/briar-android/src/org/briarproject/android/forum/ForumListItem.java b/briar-android/src/org/briarproject/android/forum/ForumListItem.java index 88a710d4e927719cd2d7ab8b6813f01f0a6a396d..281eb64b41fbffee6b382abfb97322134d10a2bf 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListItem.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListItem.java @@ -1,40 +1,27 @@ package org.briarproject.android.forum; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.ForumPostHeader; -import java.util.Collection; - +// This class is NOT thread-safe class ForumListItem { private final Forum forum; - private final boolean empty; - private final int postCount; - private final long timestamp; - private final int unread; + private int postCount, unread; + private long timestamp; - ForumListItem(Forum forum, Collection<ForumPostHeader> headers) { + ForumListItem(Forum forum, GroupCount count) { this.forum = forum; - empty = headers.isEmpty(); - if (empty) { - postCount = 0; - timestamp = 0; - unread = 0; - } else { - ForumPostHeader newest = null; - long timestamp = -1; - int unread = 0; - for (ForumPostHeader h : headers) { - if (h.getTimestamp() > timestamp) { - timestamp = h.getTimestamp(); - newest = h; - } - if (!h.isRead()) unread++; - } - this.postCount = headers.size(); - this.timestamp = newest.getTimestamp(); - this.unread = unread; - } + this.postCount = count.getMsgCount(); + this.unread = count.getUnreadCount(); + this.timestamp = count.getLatestMsgTime(); + } + + void addHeader(ForumPostHeader h) { + postCount++; + if (!h.isRead()) unread++; + if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp(); } Forum getForum() { @@ -42,7 +29,7 @@ class ForumListItem { } boolean isEmpty() { - return empty; + return postCount == 0; } int getPostCount() { diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java index ce25c8836ac5618799b7080453b1d1b8cdeaa674..0a7ffe7bd2c0b16316e0dc3ceae7cd2bb1be48f2 100644 --- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java +++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java @@ -15,9 +15,9 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.contact.ContactListAdapter; import org.briarproject.android.contact.ContactListItem; -import org.briarproject.android.contact.ConversationItem; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.view.BriarRecyclerView; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; @@ -25,21 +25,16 @@ import org.briarproject.api.db.DbException; import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; -import org.briarproject.api.introduction.IntroductionManager; -import org.briarproject.api.introduction.IntroductionMessage; -import org.briarproject.api.messaging.MessagingManager; -import org.briarproject.api.messaging.PrivateMessageHeader; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.sync.GroupId; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.logging.Logger; import javax.inject.Inject; -import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; public class ContactChooserFragment extends BaseFragment { @@ -61,9 +56,7 @@ public class ContactChooserFragment extends BaseFragment { @Inject protected volatile IdentityManager identityManager; @Inject - protected volatile MessagingManager messagingManager; - @Inject - protected volatile IntroductionManager introductionManager; + protected volatile ConversationManager conversationManager; @Inject protected volatile ConnectionRegistry connectionRegistry; @@ -159,23 +152,23 @@ public class ContactChooserFragment extends BaseFragment { public void run() { try { List<ContactListItem> contacts = new ArrayList<>(); - AuthorId localAuthorId = null; + AuthorId localAuthorId = + identityManager.getLocalAuthor().getId(); for (Contact c : contactManager.getActiveContacts()) { if (c.getId().getInt() == contactId) { c1 = c; - localAuthorId = c1.getLocalAuthorId(); } else { ContactId id = c.getId(); GroupId groupId = - messagingManager.getConversationId(id); - Collection<ConversationItem> messages = - getMessages(id); + conversationManager.getConversationId(id); + GroupCount count = + conversationManager.getGroupCount(id); boolean connected = connectionRegistry.isConnected(c.getId()); LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); contacts.add(new ContactListItem(c, localAuthor, - connected, groupId, messages)); + connected, groupId, count)); } } displayContacts(localAuthorId, contacts); @@ -220,36 +213,4 @@ public class ContactChooserFragment extends BaseFragment { builder.show(); } - /** - * This needs to be called from the DbThread - */ - private Collection<ConversationItem> getMessages(ContactId id) - throws DbException { - - long now = System.currentTimeMillis(); - - Collection<ConversationItem> messages = new ArrayList<>(); - - Collection<PrivateMessageHeader> headers = - messagingManager.getMessageHeaders(id); - for (PrivateMessageHeader h : headers) { - messages.add(ConversationItem.from(h)); - } - long duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Loading message headers took " + duration + " ms"); - - now = System.currentTimeMillis(); - Collection<IntroductionMessage> introductions = - introductionManager - .getIntroductionMessages(id); - for (IntroductionMessage m : introductions) { - messages.add(ConversationItem.from(m)); - } - duration = System.currentTimeMillis() - now; - if (LOG.isLoggable(INFO)) - LOG.info("Loading introduction messages took " + duration + " ms"); - - return messages; - } } diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java index 951b49c09809d6eced379b3ac61ea5cfe5f1d69b..893ea91262addaa7c1e18b962968a1999172d7f2 100644 --- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java @@ -3,6 +3,7 @@ package org.briarproject.android.sharing; import android.content.Context; import android.os.Build; import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.transition.Fade; import android.view.LayoutInflater; @@ -39,6 +40,7 @@ import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.android.sharing.ShareActivity.CONTACTS; import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds; +import static org.briarproject.android.sharing.ShareActivity.getContactsFromIntegers; import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; public class ContactSelectorFragment extends BaseFragment implements @@ -122,8 +124,9 @@ public class ContactSelectorFragment extends BaseFragment implements if (savedInstanceState != null) { ArrayList<Integer> intContacts = savedInstanceState.getIntegerArrayList(CONTACTS); - selectedContacts = ShareActivity.getContactsFromIntegers( - intContacts); + if (intContacts != null) { + selectedContacts = getContactsFromIntegers(intContacts); + } } return contentView; @@ -185,7 +188,7 @@ public class ContactSelectorFragment extends BaseFragment implements updateMenuItem(); } - private void loadContacts(final Collection<ContactId> selection) { + private void loadContacts(@Nullable final Collection<ContactId> selection) { shareActivity.runOnDbThread(new Runnable() { @Override public void run() { diff --git a/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java b/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java index 0d713fda2f4594b2f6c0be0b5dd4ea943a9655cc..8e76d39e705a562788528b93a0f900ed57940f89 100644 --- a/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java +++ b/briar-android/src/org/briarproject/android/sharing/SelectableContactListItem.java @@ -1,14 +1,14 @@ package org.briarproject.android.sharing; +import android.support.annotation.UiThread; + import org.briarproject.android.contact.ContactListItem; -import org.briarproject.android.contact.ConversationItem; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.GroupId; -import java.util.Collections; - -// This class is not thread-safe +// This class is NOT thread-safe public class SelectableContactListItem extends ContactListItem { private boolean selected, disabled; @@ -16,8 +16,7 @@ public class SelectableContactListItem extends ContactListItem { public SelectableContactListItem(Contact contact, LocalAuthor localAuthor, GroupId groupId, boolean selected, boolean disabled) { - super(contact, localAuthor, false, groupId, - Collections.<ConversationItem>emptyList()); + super(contact, localAuthor, false, groupId, new GroupCount(0, 0, 0)); this.selected = selected; this.disabled = disabled; diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java index 0d69fe6d293dfce17e233b07def8bf030a649ae2..422a7d16d85af5d05181c16d88a0c3a6737bad2b 100644 --- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java @@ -9,6 +9,7 @@ import org.briarproject.R; import org.briarproject.android.BriarActivity; import org.briarproject.android.contact.ContactListItem; import org.briarproject.android.view.BriarRecyclerView; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.contact.Contact; import org.briarproject.api.db.DbException; import org.briarproject.api.identity.IdentityManager; @@ -105,8 +106,8 @@ abstract class SharingStatusActivity extends BriarActivity { LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); ContactListItem item = - new ContactListItem(c, localAuthor, false, null, - null); + new ContactListItem(c, localAuthor, false, + groupId, new GroupCount(0, 0, 0)); contactItems.add(item); } } catch (DbException e) { @@ -141,8 +142,8 @@ abstract class SharingStatusActivity extends BriarActivity { LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); ContactListItem item = - new ContactListItem(c, localAuthor, false, null, - null); + new ContactListItem(c, localAuthor, false, + groupId, new GroupCount(0, 0, 0)); contactItems.add(item); } } catch (DbException e) { diff --git a/briar-android/src/org/briarproject/android/view/TextAvatarView.java b/briar-android/src/org/briarproject/android/view/TextAvatarView.java index 70ab3f3981bc18138cce89dfee9a5d6c791c0199..8b06ecb4c1cd49ffc4acd83b72f20ff08123ebb8 100644 --- a/briar-android/src/org/briarproject/android/view/TextAvatarView.java +++ b/briar-android/src/org/briarproject/android/view/TextAvatarView.java @@ -48,11 +48,12 @@ public class TextAvatarView extends FrameLayout { } public void setUnreadCount(int count) { + unreadCount = count; if (count > 0) { - this.unreadCount = count; badge.setBackgroundResource(R.drawable.bubble); badge.setText(String.valueOf(count)); - badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_text_primary_inverse)); + badge.setTextColor(ContextCompat.getColor(getContext(), + R.color.briar_text_primary_inverse)); badge.setVisibility(VISIBLE); } else { badge.setVisibility(INVISIBLE); @@ -63,12 +64,11 @@ public class TextAvatarView extends FrameLayout { if (problem) { badge.setBackgroundResource(R.drawable.bubble_problem); badge.setText("!"); - badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_primary)); + badge.setTextColor(ContextCompat + .getColor(getContext(), R.color.briar_primary)); badge.setVisibility(VISIBLE); - } else if (unreadCount > 0) { - setUnreadCount(unreadCount); } else { - badge.setVisibility(INVISIBLE); + setUnreadCount(unreadCount); } } diff --git a/briar-android/src/org/briarproject/android/view/TextInputView.java b/briar-android/src/org/briarproject/android/view/TextInputView.java index e65c519ab9ddf4eb979d15f34b18799759a378b6..e005624d2a62b58832bfa745f0a40cd71cc622a6 100644 --- a/briar-android/src/org/briarproject/android/view/TextInputView.java +++ b/briar-android/src/org/briarproject/android/view/TextInputView.java @@ -9,18 +9,13 @@ import android.support.annotation.CallSuper; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.annotation.UiThread; -import android.support.v7.widget.AppCompatImageButton; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.LinearLayout; import org.briarproject.R; import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout; @@ -32,7 +27,6 @@ import org.thoughtcrime.securesms.components.emoji.EmojiToggle; import java.util.logging.Logger; import static android.content.Context.INPUT_METHOD_SERVICE; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; @UiThread public class TextInputView extends KeyboardAwareLinearLayout diff --git a/briar-api/src/org/briarproject/api/blogs/BlogInvitationRequest.java b/briar-api/src/org/briarproject/api/blogs/BlogInvitationRequest.java index 0f2970b25825ab134f338fa414a97023eae7336a..3fc41b9ddc1c67af73565aa7be09bea9cf3bec7d 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogInvitationRequest.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogInvitationRequest.java @@ -2,8 +2,8 @@ package org.briarproject.api.blogs; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; -import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sharing.InvitationRequest; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; public class BlogInvitationRequest extends InvitationRequest { @@ -11,12 +11,12 @@ public class BlogInvitationRequest extends InvitationRequest { private final String blogAuthorName; public BlogInvitationRequest(MessageId id, SessionId sessionId, - ContactId contactId, String blogAuthorName, String message, - boolean available, long time, boolean local, boolean sent, - boolean seen, boolean read) { + GroupId groupId, ContactId contactId, String blogAuthorName, + String message, boolean available, long time, boolean local, + boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, message, available, time, local, sent, - seen, read); + super(id, sessionId, groupId, contactId, message, available, time, + local, sent, seen, read); this.blogAuthorName = blogAuthorName; } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java b/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java index e3e7cdf692c78197d81c214fcc3ef600e59522c5..3798ea75e29b2282cfe236ea40db1c9d9b5229ad 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java @@ -3,15 +3,18 @@ package org.briarproject.api.blogs; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.sharing.InvitationResponse; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; public class BlogInvitationResponse extends InvitationResponse { - public BlogInvitationResponse(MessageId id, SessionId sessionId, - ContactId contactId, boolean accept, long time, boolean local, - boolean sent, boolean seen, boolean read) { + public BlogInvitationResponse(@NotNull MessageId id, SessionId sessionId, + GroupId groupId, ContactId contactId, boolean accept, long time, + boolean local, boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, accept, time, local, sent, seen, read); + super(id, sessionId, groupId, contactId, accept, time, local, sent, + seen, read); } } diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java index 105b0d2a3f981c27db33f36fbc072b296f93689c..1465225e66136d5929a92674896e0f501c99b7b8 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java @@ -13,6 +13,7 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.TIME; public interface BlogSharingMessage { @@ -25,9 +26,9 @@ public interface BlogSharingMessage { public BlogInvitation(GroupId groupId, SessionId sessionId, String blogTitle, String blogDesc, String blogAuthorName, - byte[] blogPublicKey, String message) { + byte[] blogPublicKey, long time, String message) { - super(groupId, sessionId, message); + super(groupId, sessionId, time, message); this.blogTitle = blogTitle; this.blogDesc = blogDesc; @@ -65,9 +66,10 @@ public interface BlogSharingMessage { String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); String message = d.getOptionalString(INVITATION_MSG); + long time = d.getLong(TIME); return new BlogInvitation(groupId, sessionId, blogTitle, - blogDesc, blogAuthorName, blogPublicKey, message); + blogDesc, blogAuthorName, blogPublicKey, time, message); } public String getBlogTitle() { diff --git a/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java b/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java index 852cf0b5dc39205a718685f8e975ccd51398dad0..b77ac908d4fa7a98a850f17ef5a67bcae7cbbda7 100644 --- a/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java +++ b/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java @@ -1,17 +1,22 @@ package org.briarproject.api.clients; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; public abstract class BaseMessageHeader { private final MessageId id; + private final GroupId groupId; private final long timestamp; private final boolean local, read, sent, seen; - public BaseMessageHeader(MessageId id, long timestamp, boolean local, - boolean read, boolean sent, boolean seen) { + public BaseMessageHeader(@NotNull MessageId id, @NotNull GroupId groupId, + long timestamp, boolean local, boolean read, boolean sent, + boolean seen) { this.id = id; + this.groupId = groupId; this.timestamp = timestamp; this.local = local; this.read = read; @@ -19,10 +24,16 @@ public abstract class BaseMessageHeader { this.seen = seen; } + @NotNull public MessageId getId() { return id; } + @NotNull + public GroupId getGroupId() { + return groupId; + } + public long getTimestamp() { return timestamp; } @@ -42,4 +53,5 @@ public abstract class BaseMessageHeader { public boolean isSeen() { return seen; } + } diff --git a/briar-api/src/org/briarproject/api/clients/MessageTracker.java b/briar-api/src/org/briarproject/api/clients/MessageTracker.java index 8226a3058cfb697cd54dbf902f6a50c4f0f7c336..a73c87183fa949d61cd7858c2a6a443e99236f46 100644 --- a/briar-api/src/org/briarproject/api/clients/MessageTracker.java +++ b/briar-api/src/org/briarproject/api/clients/MessageTracker.java @@ -1,9 +1,7 @@ package org.briarproject.api.clients; import org.briarproject.api.db.DbException; -import org.briarproject.api.db.Transaction; import org.briarproject.api.sync.GroupId; -import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; public interface MessageTracker { @@ -20,19 +18,20 @@ public interface MessageTracker { void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException; class GroupCount { - private final long msgCount, unreadCount, latestMsgTime; + private final int msgCount, unreadCount; + private final long latestMsgTime; - public GroupCount(long msgCount, long unreadCount, long latestMsgTime) { + public GroupCount(int msgCount, int unreadCount, long latestMsgTime) { this.msgCount = msgCount; this.unreadCount = unreadCount; this.latestMsgTime = latestMsgTime; } - public long getMsgCount() { + public int getMsgCount() { return msgCount; } - public long getUnreadCount() { + public int getUnreadCount() { return unreadCount; } diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java index 12d8d4cc4b8dec2dd91f2cf4bf1f80322f56f421..26a2ae097d81b4a7068661990191ca1db4aceb0e 100644 --- a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java @@ -2,13 +2,16 @@ package org.briarproject.api.event; import org.briarproject.api.blogs.Blog; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sharing.InvitationRequest; -public class BlogInvitationReceivedEvent extends InvitationReceivedEvent { +public class BlogInvitationReceivedEvent extends + InvitationRequestReceivedEvent { private final Blog blog; - public BlogInvitationReceivedEvent(Blog blog, ContactId contactId) { - super(contactId); + public BlogInvitationReceivedEvent(Blog blog, ContactId contactId, + InvitationRequest request) { + super(contactId, request); this.blog = blog; } diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java index b6344ad928dd3c5e14155ad7c8dd7c70c69e3f38..fc4c04be2573bcdfce5eef8508ba6d20db2be3d7 100644 --- a/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java @@ -1,5 +1,6 @@ package org.briarproject.api.event; +import org.briarproject.api.blogs.BlogInvitationResponse; import org.briarproject.api.contact.ContactId; public class BlogInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent { @@ -7,8 +8,8 @@ public class BlogInvitationResponseReceivedEvent extends InvitationResponseRecei private final String blogTitle; public BlogInvitationResponseReceivedEvent(String blogTitle, - ContactId contactId) { - super(contactId); + ContactId contactId, BlogInvitationResponse response) { + super(contactId, response); this.blogTitle = blogTitle; } diff --git a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java index d823a2a6ba42f23fe765faee6b4fa0e5a7d0feca..3077f91605de30b7a6d8bf105f7f058e754f995a 100644 --- a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java @@ -2,17 +2,21 @@ package org.briarproject.api.event; import org.briarproject.api.contact.ContactId; import org.briarproject.api.forum.Forum; +import org.briarproject.api.forum.ForumInvitationRequest; -public class ForumInvitationReceivedEvent extends InvitationReceivedEvent { +public class ForumInvitationReceivedEvent extends + InvitationRequestReceivedEvent { private final Forum forum; - public ForumInvitationReceivedEvent(Forum forum, ContactId contactId) { - super(contactId); + public ForumInvitationReceivedEvent(Forum forum, ContactId contactId, + ForumInvitationRequest request) { + super(contactId, request); this.forum = forum; } public Forum getForum() { return forum; } + } diff --git a/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java index cb51daf0a2c05b8f97b3097a4ee7ee2eec48caf3..f4669f94620328c6ad4fcd15647c5c6ca5148624 100644 --- a/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java @@ -1,14 +1,15 @@ package org.briarproject.api.event; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.forum.ForumInvitationResponse; public class ForumInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent { private final String forumName; public ForumInvitationResponseReceivedEvent(String forumName, - ContactId contactId) { - super(contactId); + ContactId contactId, ForumInvitationResponse response) { + super(contactId, response); this.forumName = forumName; } diff --git a/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java deleted file mode 100644 index 834b71eddfc8df351bf34bdcc82d39036ad615b3..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.briarproject.api.event; - -import org.briarproject.api.contact.ContactId; - -public abstract class InvitationReceivedEvent extends Event { - - private final ContactId contactId; - - InvitationReceivedEvent(ContactId contactId) { - this.contactId = contactId; - } - - public ContactId getContactId() { - return contactId; - } -} diff --git a/briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..184a88f5387a5e8fae71d4771c7d58e1893f1e50 --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java @@ -0,0 +1,24 @@ +package org.briarproject.api.event; + +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sharing.InvitationRequest; + +public abstract class InvitationRequestReceivedEvent extends Event { + + private final ContactId contactId; + private final InvitationRequest request; + + InvitationRequestReceivedEvent(ContactId contactId, + InvitationRequest request) { + this.contactId = contactId; + this.request = request; + } + + public ContactId getContactId() { + return contactId; + } + + public InvitationRequest getRequest() { + return request; + } +} diff --git a/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java index df84a69656d5cbb38ff78843e37397eec676454d..63f41be02d538503e37521386609fcfd94ce6eb9 100644 --- a/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java @@ -1,16 +1,24 @@ package org.briarproject.api.event; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sharing.InvitationResponse; public abstract class InvitationResponseReceivedEvent extends Event { private final ContactId contactId; + private final InvitationResponse response; - public InvitationResponseReceivedEvent(ContactId contactId) { + public InvitationResponseReceivedEvent(ContactId contactId, + InvitationResponse response) { this.contactId = contactId; + this.response = response; } public ContactId getContactId() { return contactId; } + + public InvitationResponse getResponse() { + return response; + } } diff --git a/briar-api/src/org/briarproject/api/forum/ForumInvitationRequest.java b/briar-api/src/org/briarproject/api/forum/ForumInvitationRequest.java index f043ca2011c6d11374bbbefd6cfbbd88a35be730..3e90116c0b63554169b2dbc382b4fb8367c13461 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumInvitationRequest.java +++ b/briar-api/src/org/briarproject/api/forum/ForumInvitationRequest.java @@ -3,19 +3,21 @@ package org.briarproject.api.forum; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.sharing.InvitationRequest; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.Nullable; public class ForumInvitationRequest extends InvitationRequest { private final String forumName; public ForumInvitationRequest(MessageId id, SessionId sessionId, - ContactId contactId, String forumName, String message, + GroupId groupId, ContactId contactId, String forumName, String message, boolean available, long time, boolean local, boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, message, available, time, local, sent, - seen, read); + super(id, sessionId, groupId, contactId, message, available, time, + local, sent, seen, read); this.forumName = forumName; } diff --git a/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java b/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java index 00a15eac2efb8709121e86759737cc13166e4d0d..d9c49d154546febfe1041f61535a08f66e8385c7 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java +++ b/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java @@ -3,15 +3,19 @@ package org.briarproject.api.forum; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.sharing.InvitationResponse; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class ForumInvitationResponse extends InvitationResponse { - public ForumInvitationResponse(MessageId id, SessionId sessionId, - ContactId contactId, boolean accept, long time, boolean local, + public ForumInvitationResponse(@NotNull MessageId id, SessionId sessionId, + GroupId groupId, ContactId contactId, boolean accept, long time, boolean local, boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, accept, time, local, sent, seen, read); + super(id, sessionId, groupId, contactId, accept, time, local, sent, + seen, read); } } diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java index 45badea54948e5b5100263a194ed141cdd2abd5e..e93a39c6b84b782c5806f773cf83991fdc7ec974 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java +++ b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java @@ -11,6 +11,7 @@ import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.TIME; public interface ForumSharingMessage { @@ -20,9 +21,9 @@ public interface ForumSharingMessage { private final byte[] forumSalt; public ForumInvitation(GroupId groupId, SessionId sessionId, - String forumName, byte[] forumSalt, String message) { + String forumName, byte[] forumSalt, long time, String message) { - super(groupId, sessionId, message); + super(groupId, sessionId, time, message); this.forumName = forumName; this.forumSalt = forumSalt; @@ -53,9 +54,10 @@ public interface ForumSharingMessage { String forumName = d.getString(FORUM_NAME); byte[] forumSalt = d.getRaw(FORUM_SALT); String message = d.getOptionalString(INVITATION_MSG); + long time = d.getLong(TIME); return new ForumInvitation(groupId, sessionId, forumName, forumSalt, - message); + time, message); } public String getForumName() { diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java index 7ddf97aeadae65c87ed6455f01bd87bd407e3bb4..e2d968bfa119feb813900876df126b0a84b8f85c 100644 --- a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java +++ b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java @@ -1,32 +1,36 @@ package org.briarproject.api.introduction; -import org.briarproject.api.clients.SessionId; import org.briarproject.api.clients.BaseMessageHeader; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; -import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE; import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCER; - public class IntroductionMessage extends BaseMessageHeader { +public class IntroductionMessage extends BaseMessageHeader { private final SessionId sessionId; private final MessageId messageId; private final int role; - public IntroductionMessage(SessionId sessionId, MessageId messageId, - int role, long time, boolean local, boolean sent, boolean seen, + public IntroductionMessage(@NotNull SessionId sessionId, + @NotNull MessageId messageId, @NotNull GroupId groupId, int role, + long time, boolean local, boolean sent, boolean seen, boolean read) { - super(messageId, time, local, read, sent, seen); + super(messageId, groupId, time, local, read, sent, seen); this.sessionId = sessionId; this.messageId = messageId; this.role = role; } + @NotNull public SessionId getSessionId() { return sessionId; } + @NotNull public MessageId getMessageId() { return messageId; } @@ -35,9 +39,4 @@ import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRO return role == ROLE_INTRODUCER; } - public boolean isIntroducee() { - return role == ROLE_INTRODUCEE; - } - } - diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java index 912f8a3fba8ff0507e9618a55fbfe64cc07ab519..4a2910dc238092a2240e513acd16944af07734e1 100644 --- a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java +++ b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java @@ -2,21 +2,25 @@ package org.briarproject.api.introduction; import org.briarproject.api.clients.SessionId; import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class IntroductionRequest extends IntroductionResponse { private final String message; private final boolean answered, exists, introducesOtherIdentity; - public IntroductionRequest(SessionId sessionId, MessageId messageId, - int role, long time, boolean local, boolean sent, boolean seen, - boolean read, AuthorId authorId, String name, boolean accepted, - String message, boolean answered, boolean exists, + public IntroductionRequest(@NotNull SessionId sessionId, + @NotNull MessageId messageId, @NotNull GroupId groupId, int role, + long time, boolean local, boolean sent, boolean seen, boolean read, + AuthorId authorId, String name, boolean accepted, + @Nullable String message, boolean answered, boolean exists, boolean introducesOtherIdentity) { - super(sessionId, messageId, role, time, local, sent, seen, read, - authorId, name, accepted); + super(sessionId, messageId, groupId, role, time, local, sent, seen, + read, authorId, name, accepted); this.message = message; this.answered = answered; @@ -24,6 +28,7 @@ public class IntroductionRequest extends IntroductionResponse { this.introducesOtherIdentity = introducesOtherIdentity; } + @Nullable public String getMessage() { return message; } diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java index be4cb57072cabc32dcb2cfb7037c3de164a57a7a..bcb2ce3349e1fd7b02b506d78651156e20d8d753 100644 --- a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java +++ b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java @@ -2,7 +2,9 @@ package org.briarproject.api.introduction; import org.briarproject.api.clients.SessionId; import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; public class IntroductionResponse extends IntroductionMessage { @@ -10,12 +12,13 @@ public class IntroductionResponse extends IntroductionMessage { private final String name; private final boolean accepted; - public IntroductionResponse(SessionId sessionId, MessageId messageId, - int role, long time, boolean local, boolean sent, boolean seen, - boolean read, AuthorId remoteAuthorId, String name, - boolean accepted) { + public IntroductionResponse(@NotNull SessionId sessionId, + @NotNull MessageId messageId, @NotNull GroupId groupId, int role, + long time, boolean local, boolean sent, boolean seen, boolean read, + AuthorId remoteAuthorId, String name, boolean accepted) { - super(sessionId, messageId, role, time, local, sent, seen, read); + super(sessionId, messageId, groupId, role, time, local, sent, seen, + read); this.remoteAuthorId = remoteAuthorId; this.name = name; diff --git a/briar-api/src/org/briarproject/api/messaging/ConversationManager.java b/briar-api/src/org/briarproject/api/messaging/ConversationManager.java new file mode 100644 index 0000000000000000000000000000000000000000..5695af95b22ce30dd96bb5ea9c71eb2013d3f865 --- /dev/null +++ b/briar-api/src/org/briarproject/api/messaging/ConversationManager.java @@ -0,0 +1,28 @@ +package org.briarproject.api.messaging; + +import org.briarproject.api.clients.MessageTracker.GroupCount; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.sync.GroupId; + +public interface ConversationManager { + + /** + * Clients that present messages in a private conversation need to + * register themselves here. + */ + void registerConversationClient(ConversationClient client); + + /** Get the main group ID that represents this conversation */ + GroupId getConversationId(ContactId contactId) throws DbException; + + /** Get the unified group count for all private conversation messages. */ + GroupCount getGroupCount(ContactId contactId) throws DbException; + + interface ConversationClient { + GroupCount getGroupCount(Transaction txn, ContactId contactId) + throws DbException; + } + +} diff --git a/briar-api/src/org/briarproject/api/messaging/PrivateMessageHeader.java b/briar-api/src/org/briarproject/api/messaging/PrivateMessageHeader.java index e30a0ba636c91d0b4043201c61edd52202718df0..9fd76de6c8435c8030732219355a8c70d664aab7 100644 --- a/briar-api/src/org/briarproject/api/messaging/PrivateMessageHeader.java +++ b/briar-api/src/org/briarproject/api/messaging/PrivateMessageHeader.java @@ -1,17 +1,18 @@ package org.briarproject.api.messaging; import org.briarproject.api.clients.BaseMessageHeader; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; public class PrivateMessageHeader extends BaseMessageHeader { private final String contentType; - public PrivateMessageHeader(MessageId id, long timestamp, + public PrivateMessageHeader(MessageId id, GroupId groupId, long timestamp, String contentType, boolean local, boolean read, boolean sent, boolean seen) { - super(id, timestamp, local, read, sent, seen); + super(id, groupId, timestamp, local, read, sent, seen); this.contentType = contentType; } diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java index adc8d8932b38b84e19a355a2d4d384d9b8d308b3..4e6e4858f0a370f530b50f896e17ec3cafbaf8cb 100644 --- a/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java +++ b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java @@ -1,28 +1,33 @@ package org.briarproject.api.sharing; +import org.briarproject.api.clients.BaseMessageHeader; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; -import org.briarproject.api.clients.BaseMessageHeader; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; public abstract class InvitationMessage extends BaseMessageHeader { private final SessionId sessionId; private final ContactId contactId; - public InvitationMessage(MessageId id, SessionId sessionId, - ContactId contactId, long time, boolean local, boolean sent, - boolean seen, boolean read) { + public InvitationMessage(@NotNull MessageId id, + @NotNull SessionId sessionId, @NotNull GroupId groupId, + @NotNull ContactId contactId, long time, boolean local, + boolean sent, boolean seen, boolean read) { - super(id, time, local, read, sent, seen); + super(id, groupId, time, local, read, sent, seen); this.sessionId = sessionId; this.contactId = contactId; } + @NotNull public SessionId getSessionId() { return sessionId; } + @NotNull public ContactId getContactId() { return contactId; } diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java b/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java index 6d5f07d35e4ef2611c5565993fe2ec8dde96c6aa..23ed952b96d43829fa72a5149cec284bc6526e8d 100644 --- a/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java +++ b/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java @@ -2,23 +2,28 @@ package org.briarproject.api.sharing; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public abstract class InvitationRequest extends InvitationMessage { private final String message; private final boolean available; - public InvitationRequest(MessageId id, SessionId sessionId, - ContactId contactId, String message, + public InvitationRequest(@NotNull MessageId id, + @NotNull SessionId sessionId, @NotNull GroupId groupId, + @NotNull ContactId contactId, @Nullable String message, boolean available, long time, boolean local, boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, time, local, read, sent, seen); + super(id, sessionId, groupId, contactId, time, local, sent, seen, read); this.message = message; this.available = available; } + @Nullable public String getMessage() { return message; } diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java b/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java index cf4d53774e4efcadb1c4bbdedd1a2a299cf0097c..0e2d24ee65f00e1ca5f76a1108138d5c0ed9d69c 100644 --- a/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java +++ b/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java @@ -2,17 +2,19 @@ package org.briarproject.api.sharing; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; public abstract class InvitationResponse extends InvitationMessage { private final boolean accept; - public InvitationResponse(MessageId id, SessionId sessionId, - ContactId contactId, boolean accept, long time, boolean local, - boolean sent, boolean seen, boolean read) { + public InvitationResponse(@NotNull MessageId id, SessionId sessionId, + GroupId groupId, ContactId contactId, boolean accept, long time, + boolean local, boolean sent, boolean seen, boolean read) { - super(id, sessionId, contactId, time, local, read, sent, seen); + super(id, sessionId, groupId, contactId, time, local, sent, seen, read); this.accept = accept; } diff --git a/briar-api/src/org/briarproject/api/sharing/SharingConstants.java b/briar-api/src/org/briarproject/api/sharing/SharingConstants.java index e09b9015c53db9bf576ddf05db9b06b10bfd1c25..47a990669d9ebd0098341e2b89207e6455bd3035 100644 --- a/briar-api/src/org/briarproject/api/sharing/SharingConstants.java +++ b/briar-api/src/org/briarproject/api/sharing/SharingConstants.java @@ -19,6 +19,8 @@ public interface SharingConstants { String IS_SHARER = "isSharer"; String SHAREABLE_ID = "shareableId"; String INVITATION_MSG = "invitationMsg"; + String INVITATION_ID = "invitationId"; + String RESPONSE_ID = "responseId"; int SHARE_MSG_TYPE_INVITATION = 1; int SHARE_MSG_TYPE_ACCEPT = 2; int SHARE_MSG_TYPE_DECLINE = 3; diff --git a/briar-api/src/org/briarproject/api/sharing/SharingMessage.java b/briar-api/src/org/briarproject/api/sharing/SharingMessage.java index be0cac328d2a76d243dff004e071069b5f42167b..3078d86b4ef208e0d233d0e9c19c6717d25d6090 100644 --- a/briar-api/src/org/briarproject/api/sharing/SharingMessage.java +++ b/briar-api/src/org/briarproject/api/sharing/SharingMessage.java @@ -14,6 +14,7 @@ import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEP import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TIME; import static org.briarproject.api.sharing.SharingConstants.TYPE; public interface SharingMessage { @@ -21,10 +22,12 @@ public interface SharingMessage { abstract class BaseMessage { private final GroupId groupId; private final SessionId sessionId; + private final long time; - BaseMessage(GroupId groupId, SessionId sessionId) { + BaseMessage(GroupId groupId, SessionId sessionId, long time) { this.groupId = groupId; this.sessionId = sessionId; + this.time = time; } public BdfList toBdfList() { @@ -62,16 +65,20 @@ public interface SharingMessage { public SessionId getSessionId() { return sessionId; } + + public long getTime() { + return time; + } } abstract class Invitation extends BaseMessage { protected final String message; - public Invitation(GroupId groupId, SessionId sessionId, + public Invitation(GroupId groupId, SessionId sessionId, long time, String message) { - super(groupId, sessionId); + super(groupId, sessionId, time); this.message = message; } @@ -90,8 +97,9 @@ public interface SharingMessage { private final long type; - public SimpleMessage(long type, GroupId groupId, SessionId sessionId) { - super(groupId, sessionId); + public SimpleMessage(long type, GroupId groupId, SessionId sessionId, + long time) { + super(groupId, sessionId, time); this.type = type; } @@ -114,7 +122,8 @@ public interface SharingMessage { type != SHARE_MSG_TYPE_ABORT) throw new FormatException(); SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); - return new SimpleMessage(type, groupId, sessionId); + long time = d.getLong(TIME); + return new SimpleMessage(type, groupId, sessionId, time); } } diff --git a/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java b/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java index c81293ab04e0324de5f5443aa2d636f4ce616a70..575a2433d4b36569c04ea39a6259b4193313bf1c 100644 --- a/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java +++ b/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java @@ -81,8 +81,8 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook, protected void trackMessage(Transaction txn, GroupId g, long time, boolean read) throws DbException { GroupCount c = getGroupCount(txn, g); - long msgCount = c.getMsgCount() + 1; - long unreadCount = c.getUnreadCount() + (read ? 0 : 1); + int msgCount = c.getMsgCount() + 1; + int unreadCount = c.getUnreadCount() + (read ? 0 : 1); long latestTime = time > c.getLatestMsgTime() ? time : c.getLatestMsgTime(); storeGroupCount(txn, g, @@ -103,14 +103,14 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook, return count; } - private GroupCount getGroupCount(Transaction txn, GroupId g) + protected GroupCount getGroupCount(Transaction txn, GroupId g) throws DbException { GroupCount count; try { BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); count = new GroupCount( - d.getLong(GROUP_KEY_MSG_COUNT, 0L), - d.getLong(GROUP_KEY_UNREAD_COUNT, 0L), + d.getLong(GROUP_KEY_MSG_COUNT, 0L).intValue(), + d.getLong(GROUP_KEY_UNREAD_COUNT, 0L).intValue(), d.getLong(GROUP_KEY_LATEST_MSG, 0L) ); } catch (FormatException e) { diff --git a/briar-core/src/org/briarproject/clients/ConversationClientImpl.java b/briar-core/src/org/briarproject/clients/ConversationClientImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..39342b87e73bf12d0d6c27700461ce43d376a07c --- /dev/null +++ b/briar-core/src/org/briarproject/clients/ConversationClientImpl.java @@ -0,0 +1,33 @@ +package org.briarproject.clients; + +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +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.messaging.ConversationManager; +import org.briarproject.api.messaging.ConversationManager.ConversationClient; +import org.briarproject.api.sync.Group; +import org.briarproject.api.sync.GroupId; + +public abstract class ConversationClientImpl extends BdfIncomingMessageHook + implements ConversationClient { + + protected ConversationClientImpl(DatabaseComponent db, + ClientHelper clientHelper, MetadataParser metadataParser) { + super(db, clientHelper, metadataParser); + } + + protected abstract Group getContactGroup(Contact contact); + + @Override + public GroupCount getGroupCount(Transaction txn, ContactId contactId) + throws DbException { + Contact contact = db.getContact(txn, contactId); + GroupId groupId = getContactGroup(contact).getId(); + return getGroupCount(txn, groupId); + } + +} diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java index 8f77539c79faee46489301b2fe982740ad089fa3..4115fe0c09e695096360b78c5f215f285cdf3384 100644 --- a/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java +++ b/briar-core/src/org/briarproject/introduction/IntroduceeEngine.java @@ -12,6 +12,7 @@ import org.briarproject.api.introduction.IntroduceeAction; import org.briarproject.api.introduction.IntroduceeProtocolState; import org.briarproject.api.introduction.IntroductionRequest; import org.briarproject.api.clients.SessionId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import java.util.ArrayList; @@ -343,6 +344,7 @@ public class IntroduceeEngine SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID)); + GroupId groupId = new GroupId(msg.getRaw(GROUP_ID)); long time = msg.getLong(MESSAGE_TIME); String name = msg.getString(NAME); String message = msg.getOptionalString(MSG); @@ -351,8 +353,9 @@ public class IntroduceeEngine localState.getBoolean(REMOTE_AUTHOR_IS_US); IntroductionRequest ir = new IntroductionRequest(sessionId, messageId, - ROLE_INTRODUCEE, time, false, false, false, false, authorId, - name, false, message, false, exists, introducesOtherIdentity); + groupId, ROLE_INTRODUCEE, time, false, false, false, false, + authorId, name, false, message, false, exists, + introducesOtherIdentity); return new IntroductionRequestReceivedEvent(contactId, ir); } diff --git a/briar-core/src/org/briarproject/introduction/IntroducerEngine.java b/briar-core/src/org/briarproject/introduction/IntroducerEngine.java index a431fd7e46d9040696c97abd99b815341d03ee98..0f180a622f01eea69da8f3c7aa0cb0775a3e6bd6 100644 --- a/briar-core/src/org/briarproject/introduction/IntroducerEngine.java +++ b/briar-core/src/org/briarproject/introduction/IntroducerEngine.java @@ -12,6 +12,7 @@ import org.briarproject.api.introduction.IntroducerAction; import org.briarproject.api.introduction.IntroducerProtocolState; import org.briarproject.api.introduction.IntroductionResponse; import org.briarproject.api.clients.SessionId; +import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import java.util.ArrayList; @@ -298,14 +299,15 @@ public class IntroducerEngine SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID)); MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID)); + GroupId groupId = new GroupId(msg.getRaw(GROUP_ID)); long time = msg.getLong(MESSAGE_TIME); String name = getOtherContact(localState, msg); boolean accept = msg.getBoolean(ACCEPT); IntroductionResponse ir = - new IntroductionResponse(sessionId, messageId, ROLE_INTRODUCER, - time, false, false, false, false, authorId, name, - accept); + new IntroductionResponse(sessionId, messageId, groupId, + ROLE_INTRODUCER, time, false, false, false, false, + authorId, name, accept); return new IntroductionResponseReceivedEvent(contactId, ir); } diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java index 6c44e83e6bbf60d403a431bf59194c592b8f6ca3..e42ee1e0973156660b336258335e1a6ded233ba5 100644 --- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java @@ -29,7 +29,7 @@ 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.clients.ConversationClientImpl; import org.briarproject.util.StringUtils; import java.io.IOException; @@ -76,7 +76,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; import static org.briarproject.clients.BdfConstants.MSG_KEY_READ; -class IntroductionManagerImpl extends BdfIncomingMessageHook +class IntroductionManagerImpl extends ConversationClientImpl implements IntroductionManager, Client, AddContactHook, RemoveContactHook { @@ -119,7 +119,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook public void addingContact(Transaction txn, Contact c) throws DbException { try { // Create an introduction group for sending introduction messages - Group g = introductionGroupFactory.createIntroductionGroup(c); + Group g = getContactGroup(c); // Return if we've already set things up for this contact if (db.containsGroup(txn, g.getId())) return; // Store the group and share it with the contact @@ -196,7 +196,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook // remove the group (all messages will be removed with it) // this contact won't get our abort message, but the other will - db.removeGroup(txn, introductionGroupFactory.createIntroductionGroup(c)); + db.removeGroup(txn, getContactGroup(c)); } /** @@ -288,6 +288,11 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook return false; } + @Override + protected Group getContactGroup(Contact contact) { + return introductionGroupFactory.createIntroductionGroup(contact); + } + @Override public void makeIntroduction(Contact c1, Contact c2, String msg, final long timestamp) @@ -296,8 +301,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook Transaction txn = db.startTransaction(false); try { introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp); - Group g1 = introductionGroupFactory.createIntroductionGroup(c1); - Group g2 = introductionGroupFactory.createIntroductionGroup(c2); + Group g1 = getContactGroup(c1); + Group g2 = getContactGroup(c2); trackMessage(txn, g1.getId(), timestamp, true); trackMessage(txn, g2.getId(), timestamp, true); txn.setComplete(); @@ -314,7 +319,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook Transaction txn = db.startTransaction(false); try { Contact c = db.getContact(txn, contactId); - Group g = introductionGroupFactory.createIntroductionGroup(c); + Group g = getContactGroup(c); BdfDictionary state = getSessionState(txn, g.getId(), sessionId.getBytes()); @@ -334,7 +339,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook Transaction txn = db.startTransaction(false); try { Contact c = db.getContact(txn, contactId); - Group g = introductionGroupFactory.createIntroductionGroup(c); + Group g = getContactGroup(c); BdfDictionary state = getSessionState(txn, g.getId(), sessionId.getBytes()); @@ -358,9 +363,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook Transaction txn = db.startTransaction(true); try { // get messages and their status - GroupId g = introductionGroupFactory - .createIntroductionGroup(db.getContact(txn, contactId)) - .getId(); + GroupId g = getContactGroup(db.getContact(txn, contactId)).getId(); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); statuses = db.getMessageStatus(txn, contactId, g); @@ -415,7 +418,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook name = state.getString(NAME); } IntroductionResponse ir = new IntroductionResponse( - sessionId, messageId, role, time, local, + sessionId, messageId, g, role, time, local, s.isSent(), s.isSeen(), read, authorId, name, accepted); list.add(ir); @@ -445,7 +448,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook state.getBoolean(REMOTE_AUTHOR_IS_US); } IntroductionRequest ir = new IntroductionRequest( - sessionId, messageId, role, time, local, + sessionId, messageId, g, role, time, local, s.isSent(), s.isSeen(), read, authorId, name, accepted, message, answered, exists, introducesOtherIdentity); diff --git a/briar-core/src/org/briarproject/introduction/IntroductionModule.java b/briar-core/src/org/briarproject/introduction/IntroductionModule.java index 4ea0ac6c3b5a9251d6b41db231f01f02cc3409fe..989100ff8b2266f5435def18051b36bdb111dfdc 100644 --- a/briar-core/src/org/briarproject/introduction/IntroductionModule.java +++ b/briar-core/src/org/briarproject/introduction/IntroductionModule.java @@ -6,6 +6,7 @@ import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.introduction.IntroductionManager; import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.system.Clock; import javax.inject.Inject; @@ -47,6 +48,7 @@ public class IntroductionModule { LifecycleManager lifecycleManager, ContactManager contactManager, MessageQueueManager messageQueueManager, + ConversationManager conversationManager, IntroductionManagerImpl introductionManager) { lifecycleManager.registerClient(introductionManager); @@ -55,6 +57,7 @@ public class IntroductionModule { messageQueueManager.registerIncomingMessageHook( introductionManager.getClientId(), introductionManager); + conversationManager.registerConversationClient(introductionManager); return introductionManager; } diff --git a/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java b/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..670af288ed00ad9f465066b7fae0ae98fdbb3cd3 --- /dev/null +++ b/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java @@ -0,0 +1,80 @@ +package org.briarproject.messaging; + +import org.briarproject.api.clients.ContactGroupFactory; +import org.briarproject.api.clients.MessageTracker.GroupCount; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.messaging.ConversationManager; +import org.briarproject.api.sync.Group; +import org.briarproject.api.sync.GroupId; + +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.inject.Inject; + +class ConversationManagerImpl implements ConversationManager { + + private final DatabaseComponent db; + private final ContactGroupFactory contactGroupFactory; + private final Set<ConversationClient> clients; + + @Inject + ConversationManagerImpl(DatabaseComponent db, + ContactGroupFactory contactGroupFactory) { + this.db = db; + this.contactGroupFactory = contactGroupFactory; + clients = new CopyOnWriteArraySet<ConversationClient>(); + } + + @Override + public void registerConversationClient(ConversationClient client) { + if (!clients.add(client)) { + throw new IllegalStateException( + "This client is already registered"); + } + } + + @Override + public GroupId getConversationId(ContactId contactId) throws DbException { + // TODO we should probably transition this to its own group + // and/or work with the ContactId in the UI instead + Contact contact; + Transaction txn = db.startTransaction(true); + try { + contact = db.getContact(txn, contactId); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + Group group = contactGroupFactory + .createContactGroup(MessagingManagerImpl.CLIENT_ID, contact); + return group.getId(); + } + + @Override + public GroupCount getGroupCount(ContactId contactId) + throws DbException { + + int msgCount = 0, unreadCount = 0; + long latestTime = 0; + Transaction txn = db.startTransaction(true); + try { + for (ConversationClient client : clients) { + GroupCount count = client.getGroupCount(txn, contactId); + msgCount += count.getMsgCount(); + unreadCount += count.getUnreadCount(); + if (count.getLatestMsgTime() > latestTime) + latestTime = count.getLatestMsgTime(); + } + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + return new GroupCount(msgCount, unreadCount, latestTime); + } + +} diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java index d5bc6db1d374b6d70c9a9ecbc17fb8d867bca709..8a591849a24ca5643abf77ce54f12b2340cf8166 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java @@ -24,7 +24,7 @@ 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.clients.ConversationClientImpl; import org.briarproject.util.StringUtils; import java.util.ArrayList; @@ -35,7 +35,7 @@ import javax.inject.Inject; import static org.briarproject.clients.BdfConstants.MSG_KEY_READ; -class MessagingManagerImpl extends BdfIncomingMessageHook +class MessagingManagerImpl extends ConversationClientImpl implements MessagingManager, Client, AddContactHook, RemoveContactHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( @@ -77,7 +77,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook } } - private Group getContactGroup(Contact c) { + @Override + protected Group getContactGroup(Contact c) { return contactGroupFactory.createContactGroup(CLIENT_ID, c); } @@ -101,7 +102,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook boolean local = meta.getBoolean("local"); boolean read = meta.getBoolean(MSG_KEY_READ); PrivateMessageHeader header = new PrivateMessageHeader( - m.getId(), timestamp, contentType, local, read, false, false); + m.getId(), m.getGroupId(), timestamp, contentType, local, read, + false, false); PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent( header, groupId); txn.attach(event); @@ -159,9 +161,10 @@ class MessagingManagerImpl extends BdfIncomingMessageHook throws DbException { Map<MessageId, BdfDictionary> metadata; Collection<MessageStatus> statuses; + GroupId g; Transaction txn = db.startTransaction(true); try { - GroupId g = getContactGroup(db.getContact(txn, c)).getId(); + g = getContactGroup(db.getContact(txn, c)).getId(); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); statuses = db.getMessageStatus(txn, c, g); txn.setComplete(); @@ -181,8 +184,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook String contentType = meta.getString("contentType"); boolean local = meta.getBoolean("local"); boolean read = meta.getBoolean("read"); - headers.add(new PrivateMessageHeader(id, timestamp, contentType, - local, read, s.isSent(), s.isSeen())); + headers.add(new PrivateMessageHeader(id, g, timestamp, + contentType, local, read, s.isSent(), s.isSeen())); } catch (FormatException e) { throw new DbException(e); } @@ -201,4 +204,14 @@ class MessagingManagerImpl extends BdfIncomingMessageHook } } + @Override + public GroupCount getGroupCount(Transaction txn, ContactId contactId) + throws DbException { + + Contact contact = db.getContact(txn, contactId); + GroupId groupId = getContactGroup(contact).getId(); + + return getGroupCount(txn, groupId); + } + } diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java index d22782cf42b7f19d87c954721a3c0524759e160b..243042dbc49c857e88a3cc158110d9d8d19601cb 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingModule.java +++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java @@ -4,6 +4,7 @@ import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.sync.ValidationManager; @@ -22,6 +23,7 @@ public class MessagingModule { public static class EagerSingletons { @Inject MessagingManager messagingManager; + @Inject ConversationManager conversationManager; @Inject PrivateMessageValidator privateMessageValidator; } @@ -46,12 +48,22 @@ public class MessagingModule { @Singleton MessagingManager getMessagingManager(LifecycleManager lifecycleManager, ContactManager contactManager, ValidationManager validationManager, + ConversationManager conversationManager, MessagingManagerImpl messagingManager) { lifecycleManager.registerClient(messagingManager); contactManager.registerAddContactHook(messagingManager); contactManager.registerRemoveContactHook(messagingManager); validationManager .registerIncomingMessageHook(CLIENT_ID, messagingManager); + conversationManager.registerConversationClient(messagingManager); return messagingManager; } + + @Provides + @Singleton + ConversationManager getConversationManager( + ConversationManagerImpl conversationManager) { + return conversationManager; + } + } diff --git a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java index 7bb3295b7b02a925718b08ca2da3875a25d58980..58ab24a0e9331a70c9dcec5fa08485c00fb6dd4b 100644 --- a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java +++ b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java @@ -5,6 +5,8 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; @@ -21,8 +23,9 @@ public class BlogInviteeSessionState extends InviteeSessionState { public BlogInviteeSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, GroupId blogId, String blogTitle, String blogDesc, String blogAuthorName, - byte[] blogPublicKey) { - super(sessionId, storageId, groupId, state, contactId, blogId); + byte[] blogPublicKey, @NotNull MessageId invitationId) { + super(sessionId, storageId, groupId, state, contactId, blogId, + invitationId); this.blogTitle = blogTitle; this.blogDesc = blogDesc; diff --git a/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java index 16ef1355b2183ab4d45c7074fef9e4b5c37b5e41..5dd365cae718a06d1156bbaaf324b8a5bb20d647 100644 --- a/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java +++ b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java @@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.Nullable; import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; @@ -21,8 +22,9 @@ public class BlogSharerSessionState extends SharerSessionState { public BlogSharerSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, GroupId blogId, String blogTitle, String blogDesc, String blogAuthorName, - byte[] blogPublicKey) { - super(sessionId, storageId, groupId, state, contactId, blogId); + byte[] blogPublicKey, @Nullable MessageId responseId) { + super(sessionId, storageId, groupId, state, contactId, blogId, + responseId); this.blogTitle = blogTitle; this.blogDesc = blogDesc; diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java index 32314ec7305d8b6ae8d154a8686e1bf99264b177..7786dedee9cf585ec67e42c40c375b3d2b01d4b4 100644 --- a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java @@ -10,8 +10,8 @@ import org.briarproject.api.blogs.BlogManager.RemoveBlogHook; import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation; import org.briarproject.api.clients.ClientHelper; -import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.ContactGroupFactory; +import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -43,6 +43,8 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID; +import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID; class BlogSharingManagerImpl extends SharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent> @@ -108,17 +110,18 @@ class BlogSharingManagerImpl extends BlogInvitation msg, ContactId contactId, boolean available, long time, boolean local, boolean sent, boolean seen, boolean read) { - return new BlogInvitationRequest(id, msg.getSessionId(), contactId, - msg.getBlogAuthorName(), msg.getMessage(), available, time, - local, sent, seen, read); + return new BlogInvitationRequest(id, msg.getSessionId(), + msg.getGroupId(), contactId, msg.getBlogAuthorName(), + msg.getMessage(), available, time, local, sent, seen, read); } @Override protected InvitationMessage createInvitationResponse(MessageId id, - SessionId sessionId, ContactId contactId, boolean accept, long time, + SessionId sessionId, GroupId groupId, ContactId contactId, + boolean accept, long time, boolean local, boolean sent, boolean seen, boolean read) { - return new BlogInvitationResponse(id, sessionId, contactId, accept, - time, local, sent, seen, read); + return new BlogInvitationResponse(id, sessionId, groupId, contactId, + accept, time, local, sent, seen, read); } @Override @@ -163,7 +166,7 @@ class BlogSharingManagerImpl extends private final BlogFactory blogFactory; private final BlogManager blogManager; - SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory, + private SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory, BlogManager BlogManager) { this.authorFactory = authorFactory; this.blogFactory = BlogFactory; @@ -230,11 +233,13 @@ class BlogSharingManagerImpl extends } @Override - public BlogInvitation build(BlogSharerSessionState localState) { + public BlogInvitation build(BlogSharerSessionState localState, + long time) { return new BlogInvitation(localState.getGroupId(), localState.getSessionId(), localState.getBlogTitle(), localState.getBlogDesc(), localState.getBlogAuthorName(), - localState.getBlogPublicKey(), localState.getMessage()); + localState.getBlogPublicKey(), time, + localState.getMessage()); } } @@ -249,20 +254,21 @@ class BlogSharingManagerImpl extends String blogDesc = d.getString(BLOG_DESC); String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); + MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID)); return new BlogInviteeSessionState(sessionId, storageId, groupId, state, contactId, blogId, blogTitle, blogDesc, - blogAuthorName, blogPublicKey); + blogAuthorName, blogPublicKey, invitationId); } @Override public BlogInviteeSessionState build(SessionId sessionId, MessageId storageId, GroupId groupId, InviteeSessionState.State state, ContactId contactId, - Blog blog) { + Blog blog, MessageId invitationId) { return new BlogInviteeSessionState(sessionId, storageId, groupId, state, contactId, blog.getId(), blog.getName(), blog.getDescription(), blog.getAuthor().getName(), - blog.getAuthor().getPublicKey()); + blog.getAuthor().getPublicKey(), invitationId); } } @@ -277,9 +283,13 @@ class BlogSharingManagerImpl extends String blogDesc = d.getString(BLOG_DESC); String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); + MessageId responseId = null; + byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID); + if (responseIdBytes != null) + responseId = new MessageId(responseIdBytes); return new BlogSharerSessionState(sessionId, storageId, groupId, state, contactId, blogId, blogTitle, blogDesc, - blogAuthorName, blogPublicKey); + blogAuthorName, blogPublicKey, responseId); } @Override @@ -290,7 +300,7 @@ class BlogSharingManagerImpl extends return new BlogSharerSessionState(sessionId, storageId, groupId, state, contactId, blog.getId(), blog.getName(), blog.getDescription(), blog.getAuthor().getName(), - blog.getAuthor().getPublicKey()); + blog.getAuthor().getPublicKey(), null); } } @@ -299,16 +309,21 @@ class BlogSharingManagerImpl extends private final SFactory sFactory; - IRFactory(SFactory sFactory) { + private IRFactory(SFactory sFactory) { this.sFactory = sFactory; } @Override public BlogInvitationReceivedEvent build( - BlogInviteeSessionState localState) { + BlogInviteeSessionState localState, long time, String msg) { Blog blog = sFactory.parse(localState); ContactId contactId = localState.getContactId(); - return new BlogInvitationReceivedEvent(blog, contactId); + BlogInvitationRequest request = + new BlogInvitationRequest(localState.getInvitationId(), + localState.getSessionId(), localState.getGroupId(), + contactId, blog.getAuthor().getName(), msg, true, + time, false, false, false, false); + return new BlogInvitationReceivedEvent(blog, contactId, request); } } @@ -316,10 +331,18 @@ class BlogSharingManagerImpl extends InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> { @Override public BlogInvitationResponseReceivedEvent build( - BlogSharerSessionState localState) { + BlogSharerSessionState localState, boolean accept, long time) { String title = localState.getBlogTitle(); ContactId c = localState.getContactId(); - return new BlogInvitationResponseReceivedEvent(title, c); + MessageId responseId = localState.getResponseId(); + if (responseId == null) + throw new IllegalStateException("No responseId"); + BlogInvitationResponse response = + new BlogInvitationResponse(responseId, + localState.getSessionId(), localState.getGroupId(), + localState.getContactId(), accept, time, false, + false, false, false); + return new BlogInvitationResponseReceivedEvent(title, c, response); } } } diff --git a/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java index f8ac1629b121deef1f45dd777af78df2b920e9ea..79c732e932702417cea9bfdf837b1b20739111c2 100644 --- a/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java +++ b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java @@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; @@ -16,8 +17,10 @@ public class ForumInviteeSessionState extends InviteeSessionState { public ForumInviteeSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, GroupId forumId, - String forumName, byte[] forumSalt) { - super(sessionId, storageId, groupId, state, contactId, forumId); + String forumName, byte[] forumSalt, + @NotNull MessageId invitationId) { + super(sessionId, storageId, groupId, state, contactId, forumId, + invitationId); this.forumName = forumName; this.forumSalt = forumSalt; diff --git a/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java b/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java index 4e0fd05049195ba6babb25fd35eff271da46f249..1403b75a67aae8137c4fe2568cfa79a6a880d494 100644 --- a/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java +++ b/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java @@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.Nullable; import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; @@ -16,8 +17,10 @@ class ForumSharerSessionState extends SharerSessionState { ForumSharerSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, GroupId forumId, - String forumName, byte[] forumSalt) { - super(sessionId, storageId, groupId, state, contactId, forumId); + String forumName, byte[] forumSalt, + @Nullable MessageId responseId) { + super(sessionId, storageId, groupId, state, contactId, forumId, + responseId); this.forumName = forumName; this.forumSalt = forumSalt; diff --git a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java index 89bf145cc7905e2ae25f95309de364003d454250..c78cda5bcc22b4bde0bf255f89cc7128791e08b3 100644 --- a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java @@ -2,8 +2,8 @@ package org.briarproject.sharing; import org.briarproject.api.FormatException; import org.briarproject.api.clients.ClientHelper; -import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.ContactGroupFactory; +import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; @@ -35,6 +35,8 @@ import javax.inject.Inject; import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID; +import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID; class ForumSharingManagerImpl extends SharingManagerImpl<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent> @@ -82,17 +84,18 @@ class ForumSharingManagerImpl extends ForumInvitation msg, ContactId contactId, boolean available, long time, boolean local, boolean sent, boolean seen, boolean read) { - return new ForumInvitationRequest(id, msg.getSessionId(), contactId, - msg.getForumName(), msg.getMessage(), available, time, local, - sent, seen, read); + return new ForumInvitationRequest(id, msg.getSessionId(), + msg.getGroupId(), contactId, msg.getForumName(), + msg.getMessage(), available, time, local, sent, seen, read); } @Override protected InvitationMessage createInvitationResponse(MessageId id, - SessionId sessionId, ContactId contactId, boolean accept, - long time, boolean local, boolean sent, boolean seen, boolean read) { - return new ForumInvitationResponse(id, sessionId, contactId, accept, - time, local, sent, seen, read); + SessionId sessionId, GroupId groupId, ContactId contactId, + boolean accept, long time, boolean local, boolean sent, + boolean seen, boolean read) { + return new ForumInvitationResponse(id, sessionId, groupId, contactId, + accept, time, local, sent, seen, read); } @Override @@ -136,7 +139,7 @@ class ForumSharingManagerImpl extends private final ForumFactory forumFactory; private final ForumManager forumManager; - SFactory(ForumFactory forumFactory, ForumManager forumManager) { + private SFactory(ForumFactory forumFactory, ForumManager forumManager) { this.forumFactory = forumFactory; this.forumManager = forumManager; } @@ -185,10 +188,11 @@ class ForumSharingManagerImpl extends } @Override - public ForumInvitation build(ForumSharerSessionState localState) { + public ForumInvitation build(ForumSharerSessionState localState, + long time) { return new ForumInvitation(localState.getGroupId(), localState.getSessionId(), localState.getForumName(), - localState.getForumSalt(), localState.getMessage()); + localState.getForumSalt(), time, localState.getMessage()); } } @@ -201,18 +205,20 @@ class ForumSharingManagerImpl extends GroupId forumId, BdfDictionary d) throws FormatException { String forumName = d.getString(FORUM_NAME); byte[] forumSalt = d.getRaw(FORUM_SALT); + MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID)); return new ForumInviteeSessionState(sessionId, storageId, - groupId, state, contactId, forumId, forumName, forumSalt); + groupId, state, contactId, forumId, forumName, forumSalt, + invitationId); } @Override public ForumInviteeSessionState build(SessionId sessionId, MessageId storageId, GroupId groupId, InviteeSessionState.State state, ContactId contactId, - Forum forum) { + Forum forum, MessageId invitationId) { return new ForumInviteeSessionState(sessionId, storageId, groupId, state, contactId, forum.getId(), forum.getName(), - forum.getSalt()); + forum.getSalt(), invitationId); } } @@ -225,8 +231,13 @@ class ForumSharingManagerImpl extends GroupId forumId, BdfDictionary d) throws FormatException { String forumName = d.getString(FORUM_NAME); byte[] forumSalt = d.getRaw(FORUM_SALT); + MessageId responseId = null; + byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID); + if (responseIdBytes != null) + responseId = new MessageId(responseIdBytes); return new ForumSharerSessionState(sessionId, storageId, - groupId, state, contactId, forumId, forumName, forumSalt); + groupId, state, contactId, forumId, forumName, forumSalt, + responseId); } @Override @@ -236,7 +247,7 @@ class ForumSharingManagerImpl extends Forum forum) { return new ForumSharerSessionState(sessionId, storageId, groupId, state, contactId, forum.getId(), forum.getName(), - forum.getSalt()); + forum.getSalt(), null); } } @@ -245,16 +256,20 @@ class ForumSharingManagerImpl extends private final SFactory sFactory; - IRFactory(SFactory sFactory) { + private IRFactory(SFactory sFactory) { this.sFactory = sFactory; } @Override public ForumInvitationReceivedEvent build( - ForumInviteeSessionState localState) { + ForumInviteeSessionState localState, long time, String msg) { Forum forum = sFactory.parse(localState); ContactId contactId = localState.getContactId(); - return new ForumInvitationReceivedEvent(forum, contactId); + ForumInvitationRequest request = new ForumInvitationRequest( + localState.getInvitationId(), localState.getSessionId(), + localState.getGroupId(), contactId, forum.getName(), msg, + true, time, false, false, false, false); + return new ForumInvitationReceivedEvent(forum, contactId, request); } } @@ -262,10 +277,17 @@ class ForumSharingManagerImpl extends InvitationResponseReceivedEventFactory<ForumSharerSessionState, ForumInvitationResponseReceivedEvent> { @Override public ForumInvitationResponseReceivedEvent build( - ForumSharerSessionState localState) { + ForumSharerSessionState localState, boolean accept, long time) { String name = localState.getForumName(); ContactId c = localState.getContactId(); - return new ForumInvitationResponseReceivedEvent(name, c); + MessageId responseId = localState.getResponseId(); + if (responseId == null) + throw new IllegalStateException("No responseId"); + ForumInvitationResponse response = new ForumInvitationResponse( + responseId, localState.getSessionId(), + localState.getGroupId(), localState.getContactId(), accept, + time, false, false, false, false); + return new ForumInvitationResponseReceivedEvent(name, c, response); } } } diff --git a/briar-core/src/org/briarproject/sharing/InvitationFactory.java b/briar-core/src/org/briarproject/sharing/InvitationFactory.java index be82501e8f0c8d1e360eea579f3c75f45d1836d5..2c2d32c2938504279ec9431d67fcefcd64bfbac8 100644 --- a/briar-core/src/org/briarproject/sharing/InvitationFactory.java +++ b/briar-core/src/org/briarproject/sharing/InvitationFactory.java @@ -5,5 +5,5 @@ import org.briarproject.api.sharing.SharingMessage; public interface InvitationFactory<I extends SharingMessage.Invitation, SS extends SharerSessionState> extends org.briarproject.api.sharing.InvitationFactory<I> { - I build(SS localState); + I build(SS localState, long time); } diff --git a/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java index bdedeee488b931c38605c306290a21d2adce1608..9172656e9f74e1f2bc37747d1a07ff4798f6d9e8 100644 --- a/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java +++ b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java @@ -1,8 +1,8 @@ package org.briarproject.sharing; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; -public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> { +public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> { - IR build(IS localState); + IR build(IS localState, long time, String msg); } diff --git a/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java b/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java index 4420f30edd003c2727e162649fa218943a99cf91..ea5cdd91abea250acf4c633de7c08e21a432f86a 100644 --- a/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java +++ b/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java @@ -4,5 +4,5 @@ import org.briarproject.api.event.InvitationResponseReceivedEvent; public interface InvitationResponseReceivedEventFactory<SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> { - IRR build(SS localState); + IRR build(SS localState, boolean accept, long time); } diff --git a/briar-core/src/org/briarproject/sharing/InviteeEngine.java b/briar-core/src/org/briarproject/sharing/InviteeEngine.java index 766a37e4142f57a5033e9fe091c675bb43fd7f22..96af6e3207da4eb44e35a4c2d61a3cc5e76ae00b 100644 --- a/briar-core/src/org/briarproject/sharing/InviteeEngine.java +++ b/briar-core/src/org/briarproject/sharing/InviteeEngine.java @@ -3,7 +3,9 @@ package org.briarproject.sharing; import org.briarproject.api.FormatException; import org.briarproject.api.clients.ProtocolEngine; import org.briarproject.api.event.Event; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; +import org.briarproject.api.sharing.SharingMessage.Invitation; +import org.briarproject.api.system.Clock; import java.util.Collections; import java.util.List; @@ -23,16 +25,20 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREAB import static org.briarproject.api.sharing.SharingMessage.BaseMessage; import static org.briarproject.api.sharing.SharingMessage.SimpleMessage; -class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> +class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> { private static final Logger LOG = Logger.getLogger(InviteeEngine.class.getName()); private final InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory; + private final Clock clock; - InviteeEngine(InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory) { + InviteeEngine( + InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory, + Clock clock) { this.invitationReceivedEventFactory = invitationReceivedEventFactory; + this.clock = clock; } @Override @@ -63,19 +69,22 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive if (action == InviteeSessionState.Action.LOCAL_ACCEPT) { localState.setTask(TASK_ADD_SHARED_SHAREABLE); msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT, - localState.getGroupId(), localState.getSessionId()); + localState.getGroupId(), localState.getSessionId(), + clock.currentTimeMillis()); } else { localState.setTask( TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US); msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE, - localState.getGroupId(), localState.getSessionId()); + localState.getGroupId(), localState.getSessionId(), + clock.currentTimeMillis()); } messages = Collections.singletonList(msg); logLocalAction(currentState, localState, msg); } else if (action == InviteeSessionState.Action.LOCAL_LEAVE) { BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, - localState.getGroupId(), localState.getSessionId()); + localState.getGroupId(), localState.getSessionId(), + clock.currentTimeMillis()); messages = Collections.singletonList(msg); logLocalAction(currentState, localState, msg); } @@ -133,7 +142,9 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive // we have just received our invitation else if (action == InviteeSessionState.Action.REMOTE_INVITATION) { localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US); - Event event = invitationReceivedEventFactory.build(localState); + Invitation invitation = (Invitation) msg; + Event event = invitationReceivedEventFactory.build(localState, + msg.getTime(), invitation.getMessage()); events = Collections.singletonList(event); } else { @@ -203,7 +214,7 @@ class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceive localState.setState(InviteeSessionState.State.ERROR); BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(), - localState.getSessionId()); + localState.getSessionId(), clock.currentTimeMillis()); List<BaseMessage> messages = Collections.singletonList(msg); List<Event> events = Collections.emptyList(); diff --git a/briar-core/src/org/briarproject/sharing/InviteeSessionState.java b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java index 6082c7ba8dfa3100ad56d539b419f14e853cb8e3..1aa65b2320245ef655912328ef27a8c86769a9ad 100644 --- a/briar-core/src/org/briarproject/sharing/InviteeSessionState.java +++ b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java @@ -5,7 +5,9 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.NotNull; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID; import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; @@ -21,19 +23,23 @@ import static org.briarproject.sharing.InviteeSessionState.Action.REMOTE_LEAVE; public abstract class InviteeSessionState extends SharingSessionState { private State state; + @NotNull + private final MessageId invitationId; public InviteeSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, - GroupId shareableId) { + GroupId shareableId, @NotNull MessageId invitationId) { super(sessionId, storageId, groupId, contactId, shareableId); this.state = state; + this.invitationId = invitationId; } public BdfDictionary toBdfDictionary() { BdfDictionary d = super.toBdfDictionary(); d.put(STATE, getState().getValue()); d.put(IS_SHARER, false); + d.put(INVITATION_ID, invitationId); return d; } @@ -45,6 +51,11 @@ public abstract class InviteeSessionState extends SharingSessionState { return state; } + @NotNull + public MessageId getInvitationId() { + return invitationId; + } + public enum State { ERROR(0), AWAIT_INVITATION(1) { diff --git a/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java b/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java index 57b8adcfaa4359a1e4dbdddf72c3841f467fa2e2..0a514f519213cff5309b76797409261fc1c26e20 100644 --- a/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java +++ b/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java @@ -15,5 +15,6 @@ public interface InviteeSessionStateFactory<S extends Shareable, IS extends Invi GroupId shareableId, BdfDictionary d) throws FormatException; IS build(SessionId sessionId, MessageId storageId, GroupId groupId, - InviteeSessionState.State state, ContactId contactId, S shareable); + InviteeSessionState.State state, ContactId contactId, S shareable, + MessageId invitationId); } diff --git a/briar-core/src/org/briarproject/sharing/SharerEngine.java b/briar-core/src/org/briarproject/sharing/SharerEngine.java index 4f7d23f83b7af61346b88be3acfdeec81f5ea18c..3ddb17760671c8618b3a8d761d0c454aed5f01e3 100644 --- a/briar-core/src/org/briarproject/sharing/SharerEngine.java +++ b/briar-core/src/org/briarproject/sharing/SharerEngine.java @@ -4,6 +4,7 @@ import org.briarproject.api.FormatException; import org.briarproject.api.clients.ProtocolEngine; import org.briarproject.api.event.Event; import org.briarproject.api.event.InvitationResponseReceivedEvent; +import org.briarproject.api.system.Clock; import java.util.Collections; import java.util.List; @@ -22,6 +23,8 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREAB import static org.briarproject.api.sharing.SharingMessage.BaseMessage; import static org.briarproject.api.sharing.SharingMessage.Invitation; import static org.briarproject.api.sharing.SharingMessage.SimpleMessage; +import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_ACCEPT; +import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_DECLINE; class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> implements ProtocolEngine<SharerSessionState.Action, SS, BaseMessage> { @@ -32,12 +35,15 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte private final InvitationFactory<I, SS> invitationFactory; private final InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory; + private final Clock clock; SharerEngine(InvitationFactory<I, SS> invitationFactory, - InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory) { + InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory, + Clock clock) { this.invitationFactory = invitationFactory; this.invitationResponseReceivedEventFactory = invitationResponseReceivedEventFactory; + this.clock = clock; } @Override @@ -65,7 +71,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte List<Event> events = Collections.emptyList(); if (action == SharerSessionState.Action.LOCAL_INVITATION) { - BaseMessage msg = invitationFactory.build(localState); + BaseMessage msg = invitationFactory.build(localState, + clock.currentTimeMillis()); messages = Collections.singletonList(msg); logLocalAction(currentState, nextState, msg); @@ -74,7 +81,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte .setTask(TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US); } else if (action == SharerSessionState.Action.LOCAL_LEAVE) { BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, - localState.getGroupId(), localState.getSessionId()); + localState.getGroupId(), localState.getSessionId(), + clock.currentTimeMillis()); messages = Collections.singletonList(msg); logLocalAction(currentState, nextState, msg); } else { @@ -122,9 +130,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte deleteMsg = true; } // we have sent our invitation and just got a response - else if (action == SharerSessionState.Action.REMOTE_ACCEPT || - action == SharerSessionState.Action.REMOTE_DECLINE) { - if (action == SharerSessionState.Action.REMOTE_ACCEPT) { + else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) { + if (action == REMOTE_ACCEPT) { localState.setTask(TASK_SHARE_SHAREABLE); } else { // this ensures that the forum can be shared again @@ -132,7 +139,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US); } Event event = invitationResponseReceivedEventFactory - .build(localState); + .build(localState, action == REMOTE_ACCEPT, + msg.getTime()); events = Collections.singletonList(event); } else { throw new IllegalArgumentException("Bad state"); @@ -204,7 +212,8 @@ class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR exte localState.setState(SharerSessionState.State.ERROR); BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT, - localState.getGroupId(), localState.getSessionId()); + localState.getGroupId(), localState.getSessionId(), + clock.currentTimeMillis()); List<BaseMessage> messages = Collections.singletonList(msg); List<Event> events = Collections.emptyList(); diff --git a/briar-core/src/org/briarproject/sharing/SharerSessionState.java b/briar-core/src/org/briarproject/sharing/SharerSessionState.java index 6cbb271561aea089a18e2e58357d4dabc7d88472..a56be906785b5f96c63f806fbb232f7c8b3bb008 100644 --- a/briar-core/src/org/briarproject/sharing/SharerSessionState.java +++ b/briar-core/src/org/briarproject/sharing/SharerSessionState.java @@ -5,8 +5,10 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.Nullable; import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; +import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; @@ -22,20 +24,25 @@ import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_LEAVE; public abstract class SharerSessionState extends SharingSessionState { private State state; + @Nullable private String msg = null; + @Nullable + private MessageId responseId; public SharerSessionState(SessionId sessionId, MessageId storageId, GroupId groupId, State state, ContactId contactId, - GroupId shareableId) { + GroupId shareableId, @Nullable MessageId responseId) { super(sessionId, storageId, groupId, contactId, shareableId); this.state = state; + this.responseId = responseId; } public BdfDictionary toBdfDictionary() { BdfDictionary d = super.toBdfDictionary(); d.put(STATE, getState().getValue()); d.put(IS_SHARER, true); + if (responseId != null) d.put(RESPONSE_ID, responseId); return d; } @@ -55,6 +62,15 @@ public abstract class SharerSessionState extends SharingSessionState { return this.msg; } + public void setResponseId(@Nullable MessageId responseId) { + this.responseId = responseId; + } + + @Nullable + public MessageId getResponseId() { + return responseId; + } + public enum State { ERROR(0), PREPARE_INVITATION(1) { diff --git a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java index 805b9d0b4b0aad5bacf9e2147914da68efce0424..9def8487dc2b82b803b6baff9b0092062c13dc61 100644 --- a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java @@ -4,8 +4,8 @@ import org.briarproject.api.Bytes; import org.briarproject.api.FormatException; import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; -import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.ContactGroupFactory; +import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -22,7 +22,7 @@ import org.briarproject.api.db.Metadata; import org.briarproject.api.db.NoSuchMessageException; import org.briarproject.api.db.Transaction; import org.briarproject.api.event.Event; -import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationRequestReceivedEvent; import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sharing.InvitationItem; @@ -36,7 +36,7 @@ import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageStatus; import org.briarproject.api.system.Clock; -import org.briarproject.clients.BdfIncomingMessageHook; +import org.briarproject.clients.ConversationClientImpl; import org.briarproject.util.StringUtils; import java.io.IOException; @@ -85,8 +85,8 @@ import static org.briarproject.api.sharing.SharingMessage.Invitation; import static org.briarproject.clients.BdfConstants.MSG_KEY_READ; import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE; -abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent> - extends BdfIncomingMessageHook +abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationRequestReceivedEvent, IRR extends InvitationResponseReceivedEvent> + extends ConversationClientImpl implements SharingManager<S>, Client, AddContactHook, RemoveContactHook { @@ -117,13 +117,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS public abstract ClientId getClientId(); - protected abstract InvitationMessage createInvitationRequest(MessageId id, I msg, - ContactId contactId, boolean available, long time, boolean local, - boolean sent, boolean seen, boolean read); + protected abstract InvitationMessage createInvitationRequest(MessageId id, + I msg, ContactId contactId, boolean available, long time, + boolean local, boolean sent, boolean seen, boolean read); protected abstract InvitationMessage createInvitationResponse(MessageId id, - SessionId sessionId, ContactId contactId, boolean accept, long time, - boolean local, boolean sent, boolean seen, boolean read); + SessionId sessionId, GroupId groupId, ContactId contactId, + boolean accept, long time, boolean local, boolean sent, + boolean seen, boolean read); protected abstract ShareableFactory<S, I, IS, SS> getSFactory(); @@ -219,9 +220,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS checkForRaceCondition(txn, f, contact); // initialize state and process invitation - IS state = initializeInviteeState(txn, contactId, invitation); + IS state = initializeInviteeState(txn, contactId, invitation, + m.getId()); InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory()); + new InviteeEngine<IS, IR>(getIRFactory(), clock); processInviteeStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); trackIncomingMessage(txn, m); @@ -233,9 +235,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS msg.getType() == SHARE_MSG_TYPE_DECLINE) { // we are a sharer who just received a response SS state = getSessionStateForSharer(txn, sessionId); + state.setResponseId(m.getId()); SharerEngine<I, SS, IRR> engine = new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory()); + getIRRFactory(), clock); processSharerStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); trackIncomingMessage(txn, m); @@ -248,14 +251,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS SS state = (SS) s; SharerEngine<I, SS, IRR> engine = new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory()); + getIRRFactory(), clock); processSharerStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } else { // we are an invitee and the sharer wants to leave or abort IS state = (IS) s; InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory()); + new InviteeEngine<IS, IR>(getIRFactory(), clock); processInviteeStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } @@ -285,13 +288,15 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS // start engine and process its state update SharerEngine<I, SS, IRR> engine = new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory()); - processSharerStateUpdate(txn, null, + getIRRFactory(), clock); + StateUpdate<SS, BaseMessage> update = engine.onLocalAction(localState, - SharerSessionState.Action.LOCAL_INVITATION)); + SharerSessionState.Action.LOCAL_INVITATION); + processSharerStateUpdate(txn, null, update); // track message - long time = clock.currentTimeMillis(); + // TODO handle this properly without engine hacks (#376) + long time = update.toSend.get(0).getTime(); trackMessage(txn, localState.getGroupId(), time, true); txn.setComplete(); @@ -321,12 +326,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS // start engine and process its state update InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory()); - processInviteeStateUpdate(txn, null, - engine.onLocalAction(localState, localAction)); + new InviteeEngine<IS, IR>(getIRFactory(), clock); + StateUpdate<IS, BaseMessage> update = + engine.onLocalAction(localState, localAction); + processInviteeStateUpdate(txn, null, update); // track message - long time = clock.currentTimeMillis(); + // TODO handle this properly without engine hacks (#376) + long time = update.toSend.get(0).getTime(); trackMessage(txn, localState.getGroupId(), time, true); txn.setComplete(); @@ -387,8 +394,9 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS .from(getIFactory(), group.getId(), d); SessionId sessionId = msg.getSessionId(); InvitationMessage im = createInvitationResponse( - m.getKey(), sessionId, contactId, accept, time, - local, status.isSent(), status.isSeen(), read); + m.getKey(), sessionId, group.getId(), contactId, + accept, time, local, status.isSent(), + status.isSeen(), read); list.add(im); } else { @@ -555,6 +563,16 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS } } + @Override + public GroupCount getGroupCount(Transaction txn, ContactId contactId) + throws DbException { + + Contact contact = db.getContact(txn, contactId); + GroupId groupId = getContactGroup(contact).getId(); + + return getGroupCount(txn, groupId); + } + void removingShareable(Transaction txn, S f) throws DbException { try { for (Contact c : db.getContacts(txn)) { @@ -642,7 +660,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS } private IS initializeInviteeState(Transaction txn, - ContactId contactId, I msg) + ContactId contactId, I msg, MessageId id) throws FormatException, DbException { Contact c = db.getContact(txn, contactId); @@ -656,9 +674,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS Message m = clientHelper.createMessage(localGroup.getId(), now, BdfList.of(mSalt)); - IS s = getISFactory().build(msg.getSessionId(), - m.getId(), group.getId(), - InviteeSessionState.State.AWAIT_INVITATION, contactId, f); + IS s = getISFactory() + .build(msg.getSessionId(), m.getId(), group.getId(), + InviteeSessionState.State.AWAIT_INVITATION, contactId, + f, id); // save local state to database BdfDictionary d = s.toBdfDictionary(); @@ -898,19 +917,19 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS byte[] body = clientHelper.toByteArray(m.toBdfList()); Group group = db.getGroup(txn, m.getGroupId()); - long timestamp = clock.currentTimeMillis(); // add message itself as metadata BdfDictionary d = m.toBdfDictionary(); d.put(LOCAL, true); - d.put(TIME, timestamp); + d.put(TIME, m.getTime()); Metadata meta = metadataEncoder.encode(d); messageQueueManager - .sendMessage(txn, group, timestamp, body, meta); + .sendMessage(txn, group, m.getTime(), body, meta); } - private Group getContactGroup(Contact c) { + @Override + protected Group getContactGroup(Contact c) { return contactGroupFactory.createContactGroup(getClientId(), c); } @@ -930,14 +949,14 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS SharerSessionState.Action.LOCAL_LEAVE; SharerEngine<I, SS, IRR> engine = new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory()); + getIRRFactory(), clock); processSharerStateUpdate(txn, null, engine.onLocalAction((SS) state, action)); } else { InviteeSessionState.Action action = InviteeSessionState.Action.LOCAL_LEAVE; InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory()); + new InviteeEngine<IS, IR>(getIRFactory(), clock); processInviteeStateUpdate(txn, null, engine.onLocalAction((IS) state, action)); } diff --git a/briar-core/src/org/briarproject/sharing/SharingModule.java b/briar-core/src/org/briarproject/sharing/SharingModule.java index a098fa1e143a5843fe097e456c3b622836616800..da616a43d7b20c7f3e520a3e3c5c2e91ca218020 100644 --- a/briar-core/src/org/briarproject/sharing/SharingModule.java +++ b/briar-core/src/org/briarproject/sharing/SharingModule.java @@ -9,6 +9,7 @@ import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.messaging.ConversationManager; import org.briarproject.api.system.Clock; import javax.inject.Inject; @@ -52,6 +53,7 @@ public class SharingModule { LifecycleManager lifecycleManager, ContactManager contactManager, MessageQueueManager messageQueueManager, + ConversationManager conversationManager, BlogManager blogManager, BlogSharingManagerImpl blogSharingManager) { @@ -60,6 +62,7 @@ public class SharingModule { contactManager.registerRemoveContactHook(blogSharingManager); messageQueueManager.registerIncomingMessageHook( BlogSharingManagerImpl.CLIENT_ID, blogSharingManager); + conversationManager.registerConversationClient(blogSharingManager); blogManager.registerRemoveBlogHook(blogSharingManager); return blogSharingManager; @@ -86,6 +89,7 @@ public class SharingModule { LifecycleManager lifecycleManager, ContactManager contactManager, MessageQueueManager messageQueueManager, + ConversationManager conversationManager, ForumManager forumManager, ForumSharingManagerImpl forumSharingManager) { @@ -94,6 +98,7 @@ public class SharingModule { contactManager.registerRemoveContactHook(forumSharingManager); messageQueueManager.registerIncomingMessageHook( ForumSharingManagerImpl.CLIENT_ID, forumSharingManager); + conversationManager.registerConversationClient(forumSharingManager); forumManager.registerRemoveForumHook(forumSharingManager); return forumSharingManager; diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java index c02c29192bc06081234404467a633999c31ca4e2..19903224e5cb15ea301b3eef81c381f3f4497062 100644 --- a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java +++ b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java @@ -96,13 +96,13 @@ public class IntroductionManagerImplTest extends BriarTestCase { TestUtils.getRandomBytes(MESSAGE_HEADER_LENGTH + 1) ); metadataBefore = BdfDictionary.of( - new BdfEntry(GROUP_KEY_MSG_COUNT, 41L), - new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L), - new BdfEntry(GROUP_KEY_LATEST_MSG, 0L) + new BdfEntry(GROUP_KEY_MSG_COUNT, 41), + new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0), + new BdfEntry(GROUP_KEY_LATEST_MSG, 0) ); metadataAfter = BdfDictionary.of( - new BdfEntry(GROUP_KEY_MSG_COUNT, 42L), - new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L), + new BdfEntry(GROUP_KEY_MSG_COUNT, 42), + new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0), new BdfEntry(GROUP_KEY_LATEST_MSG, time) ); @@ -273,8 +273,8 @@ public class IntroductionManagerImplTest extends BriarTestCase { final BdfDictionary state = new BdfDictionary(); txn = new Transaction(null, false); - metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1L); - metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2L); + metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1); + metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2); context.checking(new Expectations() {{ oneOf(introduceeManager) @@ -314,8 +314,8 @@ public class IntroductionManagerImplTest extends BriarTestCase { txn = new Transaction(null, false); - metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41L); - metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42L); + metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41); + metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42); context.checking(new Expectations() {{ oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);