mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
8 Commits
block-inpu
...
384-conver
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3722ad840 | ||
|
|
a6de1f7144 | ||
|
|
2698e4c181 | ||
|
|
db52b2c29f | ||
|
|
f750280845 | ||
|
|
1e8784efe9 | ||
|
|
7a3bd86522 | ||
|
|
c333052396 |
@@ -36,6 +36,7 @@
|
|||||||
<string name="contact_list_button">Contacts</string>
|
<string name="contact_list_button">Contacts</string>
|
||||||
<string name="delete_contact">Delete contact</string>
|
<string name="delete_contact">Delete contact</string>
|
||||||
<string name="contact_deleted_toast">Contact deleted</string>
|
<string name="contact_deleted_toast">Contact deleted</string>
|
||||||
|
<string name="contact_deletion_failed_toast">Failed to delete contact</string>
|
||||||
<string name="forums_button">Forums</string>
|
<string name="forums_button">Forums</string>
|
||||||
<string name="settings_button">Settings</string>
|
<string name="settings_button">Settings</string>
|
||||||
<string name="sign_out_button">Sign Out</string>
|
<string name="sign_out_button">Sign Out</string>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import org.briarproject.android.contact.ConversationController;
|
||||||
|
import org.briarproject.android.contact.ConversationControllerImpl;
|
||||||
import org.briarproject.android.controller.BriarController;
|
import org.briarproject.android.controller.BriarController;
|
||||||
import org.briarproject.android.controller.BriarControllerImpl;
|
import org.briarproject.android.controller.BriarControllerImpl;
|
||||||
import org.briarproject.android.controller.ConfigController;
|
import org.briarproject.android.controller.ConfigController;
|
||||||
@@ -91,6 +93,14 @@ public class ActivityModule {
|
|||||||
return dbController;
|
return dbController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
@Provides
|
||||||
|
protected ConversationController provideConversationController(
|
||||||
|
ConversationControllerImpl conversationController) {
|
||||||
|
activity.addLifecycleController(conversationController);
|
||||||
|
return conversationController;
|
||||||
|
}
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
@Provides
|
@Provides
|
||||||
protected ForumController provideForumController(
|
protected ForumController provideForumController(
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import org.briarproject.CoreModule;
|
|||||||
import org.briarproject.android.api.AndroidExecutor;
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
import org.briarproject.android.api.ReferenceManager;
|
import org.briarproject.android.api.ReferenceManager;
|
||||||
|
import org.briarproject.android.contact.ConversationPersistentData;
|
||||||
import org.briarproject.android.forum.ForumPersistentData;
|
import org.briarproject.android.forum.ForumPersistentData;
|
||||||
import org.briarproject.android.report.BriarReportSender;
|
import org.briarproject.android.report.BriarReportSender;
|
||||||
import org.briarproject.api.contact.ContactExchangeTask;
|
import org.briarproject.api.contact.ContactExchangeTask;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
import org.briarproject.api.contact.ContactManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.crypto.CryptoExecutor;
|
import org.briarproject.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.api.crypto.PasswordStrengthEstimator;
|
import org.briarproject.api.crypto.PasswordStrengthEstimator;
|
||||||
@@ -84,6 +86,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
|||||||
|
|
||||||
ContactManager contactManager();
|
ContactManager contactManager();
|
||||||
|
|
||||||
|
ConversationManager conversationManager();
|
||||||
|
|
||||||
MessagingManager messagingManager();
|
MessagingManager messagingManager();
|
||||||
|
|
||||||
PrivateMessageFactory privateMessageFactory();
|
PrivateMessageFactory privateMessageFactory();
|
||||||
@@ -110,6 +114,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
|||||||
|
|
||||||
AndroidExecutor androidExecutor();
|
AndroidExecutor androidExecutor();
|
||||||
|
|
||||||
|
ConversationPersistentData conversationPersistentData();
|
||||||
|
|
||||||
ForumPersistentData forumPersistentData();
|
ForumPersistentData forumPersistentData();
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
|
|||||||
@@ -16,20 +16,18 @@ import org.briarproject.android.contact.ConversationActivity;
|
|||||||
import org.briarproject.android.forum.ForumActivity;
|
import org.briarproject.android.forum.ForumActivity;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
import org.briarproject.api.db.DatabaseExecutor;
|
import org.briarproject.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
|
||||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
|
||||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.api.event.IntroductionSucceededEvent;
|
import org.briarproject.api.event.IntroductionSucceededEvent;
|
||||||
import org.briarproject.api.event.MessageStateChangedEvent;
|
import org.briarproject.api.event.MessageStateChangedEvent;
|
||||||
import org.briarproject.api.event.SettingsUpdatedEvent;
|
import org.briarproject.api.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.api.forum.ForumManager;
|
import org.briarproject.api.forum.ForumManager;
|
||||||
import org.briarproject.api.lifecycle.Service;
|
import org.briarproject.api.lifecycle.Service;
|
||||||
import org.briarproject.api.lifecycle.ServiceException;
|
import org.briarproject.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.api.messaging.MessagingManager;
|
|
||||||
import org.briarproject.api.settings.Settings;
|
import org.briarproject.api.settings.Settings;
|
||||||
import org.briarproject.api.settings.SettingsManager;
|
import org.briarproject.api.settings.SettingsManager;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
@@ -75,9 +73,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidNotificationManagerImpl.class.getName());
|
Logger.getLogger(AndroidNotificationManagerImpl.class.getName());
|
||||||
|
|
||||||
|
private final ConversationManager conversationManager;
|
||||||
private final Executor dbExecutor;
|
private final Executor dbExecutor;
|
||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
private final MessagingManager messagingManager;
|
|
||||||
private final ForumManager forumManager;
|
private final ForumManager forumManager;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
@@ -94,13 +92,15 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private volatile Settings settings = new Settings();
|
private volatile Settings settings = new Settings();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AndroidNotificationManagerImpl(@DatabaseExecutor Executor dbExecutor,
|
public AndroidNotificationManagerImpl(
|
||||||
SettingsManager settingsManager, MessagingManager messagingManager,
|
ConversationManager conversationManager,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
|
SettingsManager settingsManager,
|
||||||
ForumManager forumManager, AndroidExecutor androidExecutor,
|
ForumManager forumManager, AndroidExecutor androidExecutor,
|
||||||
Application app) {
|
Application app) {
|
||||||
|
this.conversationManager = conversationManager;
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.messagingManager = messagingManager;
|
|
||||||
this.forumManager = forumManager;
|
this.forumManager = forumManager;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
appContext = app.getApplicationContext();
|
appContext = app.getApplicationContext();
|
||||||
@@ -157,27 +157,19 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
if (e instanceof SettingsUpdatedEvent) {
|
if (e instanceof SettingsUpdatedEvent) {
|
||||||
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
||||||
if (s.getNamespace().equals(SETTINGS_NAMESPACE)) loadSettings();
|
if (s.getNamespace().equals(SETTINGS_NAMESPACE)) loadSettings();
|
||||||
|
} else if (e instanceof ConversationItemReceivedEvent) {
|
||||||
|
ContactId c = ((ConversationItemReceivedEvent) e).getContactId();
|
||||||
|
showNotificationForPrivateConversation(c);
|
||||||
} else if (e instanceof MessageStateChangedEvent) {
|
} else if (e instanceof MessageStateChangedEvent) {
|
||||||
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
|
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
|
||||||
if (!m.isLocal() && m.getState() == DELIVERED) {
|
if (!m.isLocal() && m.getState() == DELIVERED) {
|
||||||
ClientId c = m.getClientId();
|
ClientId c = m.getClientId();
|
||||||
if (c.equals(messagingManager.getClientId()))
|
if (c.equals(forumManager.getClientId()))
|
||||||
showPrivateMessageNotification(m.getMessage().getGroupId());
|
|
||||||
else if (c.equals(forumManager.getClientId()))
|
|
||||||
showForumPostNotification(m.getMessage().getGroupId());
|
showForumPostNotification(m.getMessage().getGroupId());
|
||||||
}
|
}
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
|
||||||
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
|
|
||||||
showNotificationForPrivateConversation(c);
|
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
|
||||||
ContactId c = ((IntroductionResponseReceivedEvent) e).getContactId();
|
|
||||||
showNotificationForPrivateConversation(c);
|
|
||||||
} else if (e instanceof IntroductionSucceededEvent) {
|
} else if (e instanceof IntroductionSucceededEvent) {
|
||||||
Contact c = ((IntroductionSucceededEvent) e).getContact();
|
Contact c = ((IntroductionSucceededEvent) e).getContact();
|
||||||
showIntroductionSucceededNotification(c);
|
showIntroductionSucceededNotification(c);
|
||||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
|
||||||
ContactId c = ((ForumInvitationReceivedEvent) e).getContactId();
|
|
||||||
showNotificationForPrivateConversation(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +376,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
GroupId group = messagingManager.getConversationId(c);
|
GroupId group = conversationManager.getConversationId(c);
|
||||||
showPrivateMessageNotification(group);
|
showPrivateMessageNotification(group);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Application;
|
|||||||
|
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
import org.briarproject.android.api.ReferenceManager;
|
import org.briarproject.android.api.ReferenceManager;
|
||||||
|
import org.briarproject.android.contact.ConversationPersistentData;
|
||||||
import org.briarproject.android.forum.ForumPersistentData;
|
import org.briarproject.android.forum.ForumPersistentData;
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.crypto.PublicKey;
|
import org.briarproject.api.crypto.PublicKey;
|
||||||
@@ -138,6 +139,12 @@ public class AppModule {
|
|||||||
return notificationManager;
|
return notificationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ConversationPersistentData provideConversationPersistence() {
|
||||||
|
return new ConversationPersistentData();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ForumPersistentData provideForumPersistence() {
|
ForumPersistentData provideForumPersistence() {
|
||||||
|
|||||||
@@ -87,15 +87,6 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
|
|||||||
return INVALID_POSITION; // Not found
|
return INVALID_POSITION; // Not found
|
||||||
}
|
}
|
||||||
|
|
||||||
int findItemPosition(GroupId g) {
|
|
||||||
int count = getItemCount();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
ContactListItem item = getItem(i);
|
|
||||||
if (item.getGroupId().equals(g)) return i;
|
|
||||||
}
|
|
||||||
return INVALID_POSITION; // Not found
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAll(List<ContactListItem> contacts) {
|
public void addAll(List<ContactListItem> contacts) {
|
||||||
this.contacts.addAll(contacts);
|
this.contacts.addAll(contacts);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import org.briarproject.android.util.BriarRecyclerView;
|
|||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
import org.briarproject.api.contact.ContactManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.db.NoSuchContactException;
|
import org.briarproject.api.db.NoSuchContactException;
|
||||||
import org.briarproject.api.event.ContactAddedEvent;
|
import org.briarproject.api.event.ContactAddedEvent;
|
||||||
@@ -30,25 +33,16 @@ import org.briarproject.api.event.ContactConnectedEvent;
|
|||||||
import org.briarproject.api.event.ContactDisconnectedEvent;
|
import org.briarproject.api.event.ContactDisconnectedEvent;
|
||||||
import org.briarproject.api.event.ContactRemovedEvent;
|
import org.briarproject.api.event.ContactRemovedEvent;
|
||||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||||
|
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventBus;
|
import org.briarproject.api.event.EventBus;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.event.MessageStateChangedEvent;
|
|
||||||
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
import org.briarproject.api.forum.ForumSharingManager;
|
|
||||||
import org.briarproject.api.identity.IdentityManager;
|
import org.briarproject.api.identity.IdentityManager;
|
||||||
import org.briarproject.api.identity.LocalAuthor;
|
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.plugins.ConnectionRegistry;
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
import org.briarproject.api.sync.ClientId;
|
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -58,7 +52,6 @@ import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAn
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
import static org.briarproject.android.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
|
|
||||||
|
|
||||||
public class ContactListFragment extends BaseFragment implements EventListener {
|
public class ContactListFragment extends BaseFragment implements EventListener {
|
||||||
|
|
||||||
@@ -81,11 +74,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
@Inject
|
@Inject
|
||||||
protected volatile IdentityManager identityManager;
|
protected volatile IdentityManager identityManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile MessagingManager messagingManager;
|
protected volatile ConversationManager conversationManager;
|
||||||
@Inject
|
|
||||||
protected volatile IntroductionManager introductionManager;
|
|
||||||
@Inject
|
|
||||||
protected volatile ForumSharingManager forumSharingManager;
|
|
||||||
|
|
||||||
public static ContactListFragment newInstance() {
|
public static ContactListFragment newInstance() {
|
||||||
|
|
||||||
@@ -201,15 +190,21 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
try {
|
try {
|
||||||
ContactId id = c.getId();
|
ContactId id = c.getId();
|
||||||
GroupId groupId =
|
GroupId groupId =
|
||||||
messagingManager.getConversationId(id);
|
conversationManager.getConversationId(id);
|
||||||
Collection<ConversationItem> messages =
|
|
||||||
getMessages(id);
|
|
||||||
boolean connected =
|
boolean connected =
|
||||||
connectionRegistry.isConnected(c.getId());
|
connectionRegistry.isConnected(c.getId());
|
||||||
LocalAuthor localAuthor = identityManager
|
LocalAuthor localAuthor = identityManager
|
||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
|
long timestamp =
|
||||||
|
conversationManager.getTimestamp(id);
|
||||||
|
long now1 = System.currentTimeMillis();
|
||||||
|
int unread = conversationManager.getUnreadCount(id);
|
||||||
|
long duration = System.currentTimeMillis() - now1;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Loading unread messages took " +
|
||||||
|
duration + " ms");
|
||||||
contacts.add(new ContactListItem(c, localAuthor,
|
contacts.add(new ContactListItem(c, localAuthor,
|
||||||
connected, groupId, messages));
|
connected, groupId, timestamp, unread));
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
@@ -253,65 +248,28 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
} else if (e instanceof ContactRemovedEvent) {
|
} else if (e instanceof ContactRemovedEvent) {
|
||||||
LOG.info("Contact removed");
|
LOG.info("Contact removed");
|
||||||
removeItem(((ContactRemovedEvent) e).getContactId());
|
removeItem(((ContactRemovedEvent) e).getContactId());
|
||||||
} else if (e instanceof PrivateMessageReceivedEvent) {
|
} else if (e instanceof ConversationItemReceivedEvent) {
|
||||||
LOG.info("Message received, update contact");
|
LOG.info("Message received, update contact");
|
||||||
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
ConversationItemReceivedEvent event =
|
||||||
PrivateMessageHeader h = p.getMessageHeader();
|
(ConversationItemReceivedEvent) e;
|
||||||
updateItem(p.getGroupId(), ConversationItem.from(h));
|
ConversationItem item = event.getItem();
|
||||||
} else if (e instanceof MessageStateChangedEvent) {
|
updateItem(event.getContactId(), item.getTime(),
|
||||||
MessageStateChangedEvent m = (MessageStateChangedEvent) e;
|
((IncomingItem) item).isRead());
|
||||||
ClientId c = m.getClientId();
|
|
||||||
if (m.getState() == DELIVERED &&
|
|
||||||
(c.equals(introductionManager.getClientId()) ||
|
|
||||||
c.equals(forumSharingManager.getClientId()))) {
|
|
||||||
LOG.info("Message added, reloading");
|
|
||||||
reloadConversation(m.getMessage().getGroupId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloadConversation(final GroupId g) {
|
private void updateItem(final ContactId c, final long timestamp,
|
||||||
listener.runOnDbThread(new Runnable() {
|
final boolean read) {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
ContactId c = messagingManager.getContactId(g);
|
|
||||||
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() {
|
listener.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItem(position);
|
ContactListItem item = adapter.getItem(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
item.setMessages(messages);
|
if (timestamp > item.getTimestamp())
|
||||||
adapter.updateItem(position, item);
|
item.setTimestamp(timestamp);
|
||||||
}
|
if (!read)
|
||||||
}
|
item.setUnreadCount(item.getUnreadCount() + 1);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateItem(final GroupId g, final ConversationItem m) {
|
|
||||||
listener.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int position = adapter.findItemPosition(g);
|
|
||||||
ContactListItem item = adapter.getItem(position);
|
|
||||||
if (item != null) {
|
|
||||||
item.addMessage(m);
|
|
||||||
adapter.updateItem(position, item);
|
adapter.updateItem(position, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,45 +300,4 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This needs to be called from the DB thread
|
|
||||||
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<ForumInvitationMessage> invitations =
|
|
||||||
forumSharingManager.getInvitationMessages(id);
|
|
||||||
for (ForumInvitationMessage i : invitations) {
|
|
||||||
messages.add(ConversationItem.from(i));
|
|
||||||
}
|
|
||||||
duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Loading forum invitations took " + duration + " ms");
|
|
||||||
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,34 @@
|
|||||||
package org.briarproject.android.contact;
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.identity.LocalAuthor;
|
import org.briarproject.api.identity.LocalAuthor;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
public class ContactListItem {
|
public class ContactListItem {
|
||||||
|
|
||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
private final LocalAuthor localAuthor;
|
private final LocalAuthor localAuthor;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private boolean connected, empty;
|
private boolean connected;
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
private int unread;
|
private int unread;
|
||||||
|
|
||||||
public ContactListItem(Contact contact, LocalAuthor localAuthor,
|
public ContactListItem(Contact contact, LocalAuthor localAuthor,
|
||||||
boolean connected,
|
boolean connected,
|
||||||
GroupId groupId,
|
GroupId groupId,
|
||||||
Collection<ConversationItem> messages) {
|
long timestamp, int unread) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
this.localAuthor = localAuthor;
|
this.localAuthor = localAuthor;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.connected = connected;
|
this.connected = connected;
|
||||||
setMessages(messages);
|
this.timestamp = timestamp;
|
||||||
}
|
this.unread = unread;
|
||||||
|
|
||||||
void setMessages(Collection<ConversationItem> messages) {
|
|
||||||
empty = messages == null || messages.isEmpty();
|
|
||||||
timestamp = 0;
|
|
||||||
unread = 0;
|
|
||||||
if (!empty) {
|
|
||||||
for (ConversationItem i : messages) {
|
|
||||||
addMessage(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addMessage(ConversationItem message) {
|
|
||||||
empty = empty && message == null;
|
|
||||||
if (message != null) {
|
|
||||||
if (message.getTime() > timestamp) timestamp = message.getTime();
|
|
||||||
if (message instanceof IncomingItem &&
|
|
||||||
!((IncomingItem) message).isRead())
|
|
||||||
unread++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contact getContact() {
|
public Contact getContact() {
|
||||||
@@ -71,14 +52,22 @@ public class ContactListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
return empty;
|
return timestamp < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getTimestamp() {
|
long getTimestamp() {
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTimestamp(long timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
int getUnreadCount() {
|
int getUnreadCount() {
|
||||||
return unread;
|
return unread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUnreadCount(int unread) {
|
||||||
|
this.unread = unread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,40 +27,12 @@ import org.briarproject.R;
|
|||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.BriarActivity;
|
import org.briarproject.android.BriarActivity;
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
import org.briarproject.android.introduction.IntroductionActivity;
|
import org.briarproject.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.android.util.BriarRecyclerView;
|
import org.briarproject.android.util.BriarRecyclerView;
|
||||||
import org.briarproject.api.FormatException;
|
|
||||||
import org.briarproject.api.clients.SessionId;
|
|
||||||
import org.briarproject.api.contact.Contact;
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
import org.briarproject.api.crypto.CryptoExecutor;
|
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
||||||
import org.briarproject.api.db.DbException;
|
|
||||||
import org.briarproject.api.db.NoSuchContactException;
|
|
||||||
import org.briarproject.api.db.NoSuchMessageException;
|
|
||||||
import org.briarproject.api.event.ContactConnectedEvent;
|
|
||||||
import org.briarproject.api.event.ContactDisconnectedEvent;
|
|
||||||
import org.briarproject.api.event.ContactRemovedEvent;
|
|
||||||
import org.briarproject.api.event.Event;
|
|
||||||
import org.briarproject.api.event.EventBus;
|
|
||||||
import org.briarproject.api.event.EventListener;
|
|
||||||
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
|
||||||
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
|
||||||
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.api.event.MessagesAckedEvent;
|
|
||||||
import org.briarproject.api.event.MessagesSentEvent;
|
|
||||||
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
import org.briarproject.api.forum.ForumSharingManager;
|
|
||||||
import org.briarproject.api.introduction.IntroductionManager;
|
|
||||||
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.PrivateMessage;
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageFactory;
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
@@ -68,12 +40,9 @@ import org.briarproject.util.StringUtils;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -84,13 +53,11 @@ import im.delight.android.identicons.IdenticonDrawable;
|
|||||||
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
|
|
||||||
|
|
||||||
public class ConversationActivity extends BriarActivity
|
public class ConversationActivity extends BriarActivity
|
||||||
implements EventListener, OnClickListener,
|
implements ConversationController.ConversationListener, OnClickListener,
|
||||||
ConversationAdapter.IntroductionHandler {
|
ConversationAdapter.ConversationHandler,
|
||||||
|
ConversationAdapter.MessageUpdatedHandler {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConversationActivity.class.getName());
|
Logger.getLogger(ConversationActivity.class.getName());
|
||||||
@@ -98,11 +65,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManager notificationManager;
|
AndroidNotificationManager notificationManager;
|
||||||
@Inject
|
|
||||||
ConnectionRegistry connectionRegistry;
|
|
||||||
@Inject
|
|
||||||
@CryptoExecutor
|
|
||||||
protected Executor cryptoExecutor;
|
|
||||||
|
|
||||||
private ConversationAdapter adapter;
|
private ConversationAdapter adapter;
|
||||||
private CircleImageView toolbarAvatar;
|
private CircleImageView toolbarAvatar;
|
||||||
@@ -114,24 +76,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ContactManager contactManager;
|
protected volatile ConversationController conversationController;
|
||||||
@Inject
|
|
||||||
protected volatile MessagingManager messagingManager;
|
|
||||||
@Inject
|
|
||||||
protected volatile EventBus eventBus;
|
|
||||||
@Inject
|
|
||||||
volatile PrivateMessageFactory privateMessageFactory;
|
|
||||||
@Inject
|
|
||||||
protected volatile IntroductionManager introductionManager;
|
|
||||||
@Inject
|
|
||||||
protected volatile ForumSharingManager forumSharingManager;
|
|
||||||
|
|
||||||
private volatile GroupId groupId = null;
|
private volatile GroupId groupId = null;
|
||||||
private volatile ContactId contactId = null;
|
|
||||||
private volatile String contactName = null;
|
|
||||||
private volatile byte[] contactIdenticonKey = null;
|
|
||||||
private volatile boolean connected = false;
|
|
||||||
private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -165,7 +112,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ViewCompat.setTransitionName(toolbarAvatar, "avatar" + hexGroupId);
|
ViewCompat.setTransitionName(toolbarAvatar, "avatar" + hexGroupId);
|
||||||
ViewCompat.setTransitionName(toolbarStatus, "bulb" + hexGroupId);
|
ViewCompat.setTransitionName(toolbarStatus, "bulb" + hexGroupId);
|
||||||
|
|
||||||
adapter = new ConversationAdapter(this, this);
|
adapter = new ConversationAdapter(this, this, this);
|
||||||
list = (BriarRecyclerView) findViewById(R.id.conversationView);
|
list = (BriarRecyclerView) findViewById(R.id.conversationView);
|
||||||
list.setLayoutManager(new LinearLayoutManager(this));
|
list.setLayoutManager(new LinearLayoutManager(this));
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
@@ -179,6 +126,22 @@ public class ConversationActivity extends BriarActivity
|
|||||||
sendButton.setEnabled(false);
|
sendButton.setEnabled(false);
|
||||||
sendButton.setOnClickListener(this);
|
sendButton.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conversationController
|
||||||
|
.loadConversation(groupId, new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean result) {
|
||||||
|
if (result) {
|
||||||
|
displayContactDetails();
|
||||||
|
// Load the messages here to make sure we have a
|
||||||
|
// contactId
|
||||||
|
loadMessages();
|
||||||
|
} else {
|
||||||
|
// TODO Maybe an error dialog ?
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,16 +164,13 @@ public class ConversationActivity extends BriarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
eventBus.addListener(this);
|
|
||||||
notificationManager.blockNotification(groupId);
|
notificationManager.blockNotification(groupId);
|
||||||
notificationManager.clearPrivateMessageNotification(groupId);
|
notificationManager.clearPrivateMessageNotification(groupId);
|
||||||
loadData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
eventBus.removeListener(this);
|
|
||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
if (isFinishing()) markMessagesRead();
|
if (isFinishing()) markMessagesRead();
|
||||||
}
|
}
|
||||||
@@ -221,8 +181,16 @@ public class ConversationActivity extends BriarActivity
|
|||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.conversation_actions, menu);
|
inflater.inflate(R.menu.conversation_actions, menu);
|
||||||
|
|
||||||
hideIntroductionActionWhenOneContact(
|
final MenuItem introduction = menu.findItem(R.id.action_introduction);
|
||||||
menu.findItem(R.id.action_introduction));
|
conversationController.shouldHideIntroductionAction(
|
||||||
|
new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean result) {
|
||||||
|
if (result) {
|
||||||
|
introduction.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
@@ -235,6 +203,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
onBackPressed();
|
onBackPressed();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_introduction:
|
case R.id.action_introduction:
|
||||||
|
ContactId contactId = conversationController.getContactId();
|
||||||
if (contactId == null) return false;
|
if (contactId == null) return false;
|
||||||
Intent intent = new Intent(this, IntroductionActivity.class);
|
Intent intent = new Intent(this, IntroductionActivity.class);
|
||||||
intent.putExtra(IntroductionActivity.CONTACT_ID,
|
intent.putExtra(IntroductionActivity.CONTACT_ID,
|
||||||
@@ -260,46 +229,18 @@ public class ConversationActivity extends BriarActivity
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData() {
|
/**
|
||||||
runOnDbThread(new Runnable() {
|
* This should only be called after the conversation has been loaded.
|
||||||
@Override
|
*/
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (contactId == null)
|
|
||||||
contactId = messagingManager.getContactId(groupId);
|
|
||||||
if (contactName == null || contactIdenticonKey == null) {
|
|
||||||
Contact contact = contactManager.getContact(contactId);
|
|
||||||
contactName = contact.getAuthor().getName();
|
|
||||||
contactIdenticonKey =
|
|
||||||
contact.getAuthor().getId().getBytes();
|
|
||||||
}
|
|
||||||
connected = connectionRegistry.isConnected(contactId);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Loading contact took " + duration + " ms");
|
|
||||||
displayContactDetails();
|
|
||||||
// Load the messages here to make sure we have a contactId
|
|
||||||
loadMessages();
|
|
||||||
} catch (NoSuchContactException e) {
|
|
||||||
finishOnUiThread();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayContactDetails() {
|
private void displayContactDetails() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
toolbarAvatar.setImageDrawable(
|
toolbarAvatar.setImageDrawable(new IdenticonDrawable(
|
||||||
new IdenticonDrawable(contactIdenticonKey));
|
conversationController.getContactIdenticonKey()));
|
||||||
toolbarTitle.setText(contactName);
|
toolbarTitle.setText(conversationController.getContactName());
|
||||||
|
|
||||||
if (connected) {
|
if (conversationController.isConnected()) {
|
||||||
toolbarStatus.setImageDrawable(ContextCompat
|
toolbarStatus.setImageDrawable(ContextCompat
|
||||||
.getDrawable(ConversationActivity.this,
|
.getDrawable(ConversationActivity.this,
|
||||||
R.drawable.contact_online));
|
R.drawable.contact_online));
|
||||||
@@ -312,125 +253,30 @@ public class ConversationActivity extends BriarActivity
|
|||||||
toolbarStatus
|
toolbarStatus
|
||||||
.setContentDescription(getString(R.string.offline));
|
.setContentDescription(getString(R.string.offline));
|
||||||
}
|
}
|
||||||
adapter.setContactName(contactName);
|
adapter.setContactName(conversationController.getContactName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessages() {
|
private void loadMessages() {
|
||||||
runOnDbThread(new Runnable() {
|
conversationController.loadMessages(new UiResultHandler<Boolean>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void onResultUi(Boolean result) {
|
||||||
try {
|
if (result) {
|
||||||
long now = System.currentTimeMillis();
|
List<ConversationItem> items =
|
||||||
if (contactId == null)
|
conversationController.getConversationItems();
|
||||||
contactId = messagingManager.getContactId(groupId);
|
sendButton.setEnabled(true);
|
||||||
Collection<PrivateMessageHeader> headers =
|
if (items.isEmpty()) {
|
||||||
messagingManager.getMessageHeaders(contactId);
|
// we have no messages,
|
||||||
Collection<IntroductionMessage> introductions =
|
// so let the list know to hide progress bar
|
||||||
introductionManager
|
list.showData();
|
||||||
.getIntroductionMessages(contactId);
|
} else {
|
||||||
Collection<ForumInvitationMessage> invitations =
|
adapter.addAll(items);
|
||||||
forumSharingManager
|
// Scroll to the bottom
|
||||||
.getInvitationMessages(contactId);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Loading headers took " + duration + " ms");
|
|
||||||
displayMessages(headers, introductions, invitations);
|
|
||||||
} catch (NoSuchContactException e) {
|
|
||||||
finishOnUiThread();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayMessages(final Collection<PrivateMessageHeader> headers,
|
|
||||||
final Collection<IntroductionMessage> introductions,
|
|
||||||
final Collection<ForumInvitationMessage> invitations) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendButton.setEnabled(true);
|
|
||||||
if (headers.isEmpty() && introductions.isEmpty() &&
|
|
||||||
invitations.isEmpty()) {
|
|
||||||
// we have no messages,
|
|
||||||
// so let the list know to hide progress bar
|
|
||||||
list.showData();
|
|
||||||
} else {
|
|
||||||
List<ConversationItem> items = new ArrayList<>();
|
|
||||||
for (PrivateMessageHeader h : headers) {
|
|
||||||
ConversationMessageItem item =
|
|
||||||
(ConversationMessageItem) ConversationItem
|
|
||||||
.from(h);
|
|
||||||
byte[] body = bodyCache.get(h.getId());
|
|
||||||
if (body == null) loadMessageBody(h);
|
|
||||||
else item.setBody(body);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
for (IntroductionMessage m : introductions) {
|
|
||||||
ConversationItem item;
|
|
||||||
if (m instanceof IntroductionRequest) {
|
|
||||||
item = ConversationItem
|
|
||||||
.from((IntroductionRequest) m);
|
|
||||||
} else {
|
|
||||||
item = ConversationItem
|
|
||||||
.from(ConversationActivity.this,
|
|
||||||
contactName,
|
|
||||||
(IntroductionResponse) m);
|
|
||||||
}
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
for (ForumInvitationMessage i : invitations) {
|
|
||||||
ConversationItem item = ConversationItem.from(i);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
adapter.addAll(items);
|
|
||||||
// Scroll to the bottom
|
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadMessageBody(final PrivateMessageHeader h) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
byte[] body = messagingManager.getMessageBody(h.getId());
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Loading message took " + duration + " ms");
|
|
||||||
displayMessageBody(h.getId(), body);
|
|
||||||
} catch (NoSuchMessageException e) {
|
|
||||||
// The item will be removed when we get the event
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayMessageBody(final MessageId m, final byte[] body) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
bodyCache.put(m, body);
|
|
||||||
SparseArray<ConversationMessageItem> messages =
|
|
||||||
adapter.getPrivateMessages();
|
|
||||||
for (int i = 0; i < messages.size(); i++) {
|
|
||||||
ConversationMessageItem item = messages.valueAt(i);
|
|
||||||
if (item.getId().equals(m)) {
|
|
||||||
item.setBody(body);
|
|
||||||
adapter.notifyItemChanged(messages.keyAt(i));
|
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -448,151 +294,56 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void markMessagesRead() {
|
private void markMessagesRead() {
|
||||||
List<MessageId> unread = new ArrayList<>();
|
List<ConversationItem> unread = new ArrayList<>();
|
||||||
SparseArray<IncomingItem> list = adapter.getIncomingMessages();
|
SparseArray<IncomingItem> list = adapter.getIncomingMessages();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
IncomingItem item = list.valueAt(i);
|
IncomingItem item = list.valueAt(i);
|
||||||
if (!item.isRead()) unread.add(item.getId());
|
if (!item.isRead()) unread.add(item);
|
||||||
}
|
}
|
||||||
if (unread.isEmpty()) return;
|
if (unread.isEmpty()) return;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking " + unread.size() + " messages read");
|
LOG.info("Marking " + unread.size() + " messages read");
|
||||||
markMessagesRead(Collections.unmodifiableList(unread));
|
conversationController.markMessagesRead(
|
||||||
|
Collections.unmodifiableList(unread),
|
||||||
|
new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean result) {
|
||||||
|
// TODO something?
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessagesRead(final Collection<MessageId> unread) {
|
private void markMessageReadIfNew(final ConversationItem item) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
ConversationItem last = adapter.getLastItem();
|
||||||
long now = System.currentTimeMillis();
|
if (last != null) {
|
||||||
for (MessageId m : unread)
|
// Mark the message read if it's the newest message
|
||||||
// not really clean, but the messaging manager can
|
long lastMsgTime = last.getTime();
|
||||||
// handle introduction messages as well
|
long newMsgTime = item.getTime();
|
||||||
messagingManager.setReadFlag(m, true);
|
if (newMsgTime > lastMsgTime)
|
||||||
long duration = System.currentTimeMillis() - now;
|
conversationController.markNewMessageRead(item);
|
||||||
if (LOG.isLoggable(INFO))
|
} else {
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
// mark the message as read as well if it is the first one
|
||||||
} catch (DbException e) {
|
conversationController.markNewMessageRead(item);
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
}
|
||||||
|
loadMessages();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void markMessages(final Collection<MessageId> messageIds,
|
||||||
if (e instanceof ContactRemovedEvent) {
|
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact removed");
|
|
||||||
finishOnUiThread();
|
|
||||||
}
|
|
||||||
} else if (e instanceof PrivateMessageReceivedEvent) {
|
|
||||||
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
|
||||||
if (p.getGroupId().equals(groupId)) {
|
|
||||||
LOG.info("Message received, adding");
|
|
||||||
PrivateMessageHeader h = p.getMessageHeader();
|
|
||||||
addConversationItem(ConversationItem.from(h));
|
|
||||||
loadMessageBody(h);
|
|
||||||
markMessageReadIfNew(h);
|
|
||||||
}
|
|
||||||
} else if (e instanceof MessagesSentEvent) {
|
|
||||||
MessagesSentEvent m = (MessagesSentEvent) e;
|
|
||||||
if (m.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Messages sent");
|
|
||||||
markMessages(m.getMessageIds(), true, false);
|
|
||||||
}
|
|
||||||
} else if (e instanceof MessagesAckedEvent) {
|
|
||||||
MessagesAckedEvent m = (MessagesAckedEvent) e;
|
|
||||||
if (m.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Messages acked");
|
|
||||||
markMessages(m.getMessageIds(), true, true);
|
|
||||||
}
|
|
||||||
} else if (e instanceof ContactConnectedEvent) {
|
|
||||||
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact connected");
|
|
||||||
connected = true;
|
|
||||||
displayContactDetails();
|
|
||||||
}
|
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
|
||||||
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact disconnected");
|
|
||||||
connected = false;
|
|
||||||
displayContactDetails();
|
|
||||||
}
|
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
|
||||||
IntroductionRequestReceivedEvent event =
|
|
||||||
(IntroductionRequestReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
IntroductionRequest ir = event.getIntroductionRequest();
|
|
||||||
ConversationItem item = new ConversationIntroductionInItem(ir);
|
|
||||||
addConversationItem(item);
|
|
||||||
}
|
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
|
||||||
IntroductionResponseReceivedEvent event =
|
|
||||||
(IntroductionResponseReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
IntroductionResponse ir = event.getIntroductionResponse();
|
|
||||||
ConversationItem item =
|
|
||||||
ConversationItem.from(this, contactName, ir);
|
|
||||||
addConversationItem(item);
|
|
||||||
}
|
|
||||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
|
||||||
ForumInvitationReceivedEvent event =
|
|
||||||
(ForumInvitationReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
loadMessages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markMessageReadIfNew(final PrivateMessageHeader h) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ConversationItem item = adapter.getLastItem();
|
|
||||||
if (item != null) {
|
|
||||||
// Mark the message read if it's the newest message
|
|
||||||
long lastMsgTime = item.getTime();
|
|
||||||
long newMsgTime = h.getTimestamp();
|
|
||||||
if (newMsgTime > lastMsgTime) markNewMessageRead(h.getId());
|
|
||||||
else loadMessages();
|
|
||||||
} else {
|
|
||||||
// mark the message as read as well if it is the first one
|
|
||||||
markNewMessageRead(h.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markNewMessageRead(final MessageId m) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
messagingManager.setReadFlag(m, true);
|
|
||||||
loadMessages();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markMessages(final Collection<MessageId> messageIds,
|
|
||||||
final boolean sent, final boolean seen) {
|
final boolean sent, final boolean seen) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Set<MessageId> messages = new HashSet<>(messageIds);
|
Set<MessageId> messages = new HashSet<>(messageIds);
|
||||||
SparseArray<OutgoingItem> list = adapter.getOutgoingMessages();
|
SparseArray<ConversationItem.OutgoingItem> list =
|
||||||
|
adapter.getOutgoingMessages();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
OutgoingItem item = list.valueAt(i);
|
ConversationItem.OutgoingItem item = list.valueAt(i);
|
||||||
if (messages.contains(item.getId())) {
|
if (messages.contains(item.getId())) {
|
||||||
item.setSent(sent);
|
item.setSent(sent);
|
||||||
item.setSeen(seen);
|
item.setSeen(seen);
|
||||||
@@ -603,6 +354,12 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ConversationItem item) {
|
||||||
|
addConversationItem(item);
|
||||||
|
markMessageReadIfNew(item);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
markMessagesRead();
|
markMessagesRead();
|
||||||
@@ -621,46 +378,14 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createMessage(final byte[] body, final long timestamp) {
|
private void createMessage(final byte[] body, final long timestamp) {
|
||||||
cryptoExecutor.execute(new Runnable() {
|
conversationController.createMessage(body, timestamp,
|
||||||
@Override
|
new UiResultHandler<ConversationItem>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
try {
|
public void onResultUi(ConversationItem item) {
|
||||||
storeMessage(privateMessageFactory
|
if (item != null)
|
||||||
.createPrivateMessage(groupId, timestamp, null,
|
addConversationItem(item);
|
||||||
"text/plain", body), body);
|
}
|
||||||
} catch (FormatException e) {
|
});
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMessage(final PrivateMessage m, final byte[] body) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
messagingManager.addLocalMessage(m);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Storing message took " + duration + " ms");
|
|
||||||
|
|
||||||
PrivateMessageHeader h = new PrivateMessageHeader(
|
|
||||||
m.getMessage().getId(),
|
|
||||||
m.getMessage().getTimestamp(), m.getContentType(),
|
|
||||||
true, false, false, false);
|
|
||||||
ConversationMessageItem item =
|
|
||||||
(ConversationMessageItem) ConversationItem.from(h);
|
|
||||||
item.setBody(body);
|
|
||||||
bodyCache.put(m.getMessage().getId(), body);
|
|
||||||
addConversationItem(item);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askToRemoveContact() {
|
private void askToRemoveContact() {
|
||||||
@@ -682,89 +407,42 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeContact() {
|
private void removeContact() {
|
||||||
runOnDbThread(new Runnable() {
|
conversationController
|
||||||
@Override
|
.removeContact(new UiResultHandler<Boolean>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
try {
|
public void onResultUi(Boolean result) {
|
||||||
// make sure contactId is initialised
|
if (result) {
|
||||||
if (contactId == null)
|
String deleted =
|
||||||
contactId = messagingManager.getContactId(groupId);
|
getString(R.string.contact_deleted_toast);
|
||||||
// remove contact with that ID
|
Toast.makeText(ConversationActivity.this, deleted,
|
||||||
contactManager.removeContact(contactId);
|
LENGTH_SHORT)
|
||||||
} catch (DbException e) {
|
.show();
|
||||||
if (LOG.isLoggable(WARNING))
|
finish();
|
||||||
LOG.log(WARNING, e.toString(), e);
|
} else {
|
||||||
} finally {
|
String failed = getString(
|
||||||
finishAfterContactRemoved();
|
R.string.contact_deletion_failed_toast);
|
||||||
}
|
Toast.makeText(ConversationActivity.this, failed,
|
||||||
}
|
LENGTH_SHORT).show();
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void finishAfterContactRemoved() {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String deleted = getString(R.string.contact_deleted_toast);
|
|
||||||
Toast.makeText(ConversationActivity.this, deleted, LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideIntroductionActionWhenOneContact(final MenuItem item) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (contactManager.getActiveContacts().size() < 2) {
|
|
||||||
hideIntroductionAction(item);
|
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
});
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideIntroductionAction(final MenuItem item) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
item.setVisible(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void respondToIntroduction(final SessionId sessionId,
|
public void respondToItem(ConversationItem item, boolean accept) {
|
||||||
final boolean accept) {
|
long minTimestamp = getMinTimestampForNewMessage();
|
||||||
runOnDbThread(new Runnable() {
|
conversationController.respondToItem(item, accept, minTimestamp,
|
||||||
@Override
|
new UiResultHandler<Boolean>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
long timestamp = System.currentTimeMillis();
|
public void onResultUi(Boolean result) {
|
||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
if (result) {
|
||||||
try {
|
loadMessages();
|
||||||
if (accept) {
|
} else {
|
||||||
introductionManager
|
// TODO decide how to make this type-agnostic
|
||||||
.acceptIntroduction(contactId, sessionId,
|
introductionResponseError();
|
||||||
timestamp);
|
}
|
||||||
} else {
|
|
||||||
introductionManager
|
|
||||||
.declineIntroduction(contactId, sessionId,
|
|
||||||
timestamp);
|
|
||||||
}
|
}
|
||||||
loadMessages();
|
});
|
||||||
} catch (DbException | FormatException e) {
|
|
||||||
introductionResponseError();
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void introductionResponseError() {
|
private void introductionResponseError() {
|
||||||
@@ -778,4 +456,20 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageUpdated(final int position) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adapter.notifyItemChanged(position);
|
||||||
|
// Scroll to the bottom
|
||||||
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contactUpdated() {
|
||||||
|
displayContactDetails();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,27 +15,26 @@ import android.widget.TextView;
|
|||||||
import org.briarproject.R;
|
import org.briarproject.R;
|
||||||
import org.briarproject.android.forum.ForumInvitationsActivity;
|
import org.briarproject.android.forum.ForumInvitationsActivity;
|
||||||
import org.briarproject.android.util.AndroidUtils;
|
import org.briarproject.android.util.AndroidUtils;
|
||||||
import org.briarproject.api.clients.SessionId;
|
import org.briarproject.api.UniqueId;
|
||||||
|
import org.briarproject.api.conversation.ConversationForumInvitationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionRequestItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionResponseItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.OutgoingItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationMessageItem;
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
import org.briarproject.api.introduction.IntroductionRequest;
|
||||||
|
import org.briarproject.api.introduction.IntroductionResponse;
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||||
|
import static android.support.v7.widget.RecyclerView.NO_ID;
|
||||||
import static android.support.v7.widget.RecyclerView.ViewHolder;
|
import static android.support.v7.widget.RecyclerView.ViewHolder;
|
||||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_IN;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.FORUM_INVITATION_OUT;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_IN;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.INTRODUCTION_OUT;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.MSG_IN;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.MSG_IN_UNREAD;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.MSG_OUT;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.NOTICE_IN;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.NOTICE_OUT;
|
|
||||||
import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
|
|
||||||
|
|
||||||
class ConversationAdapter extends RecyclerView.Adapter {
|
class ConversationAdapter extends RecyclerView.Adapter {
|
||||||
|
|
||||||
@@ -43,13 +42,17 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
new SortedList<>(ConversationItem.class, new ListCallbacks());
|
new SortedList<>(ConversationItem.class, new ListCallbacks());
|
||||||
|
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
private IntroductionHandler intro;
|
private ConversationHandler handler;
|
||||||
|
private MessageUpdatedHandler msgUpdated;
|
||||||
private String contactName;
|
private String contactName;
|
||||||
|
|
||||||
public ConversationAdapter(Context context,
|
public ConversationAdapter(Context context,
|
||||||
IntroductionHandler introductionHandler) {
|
ConversationHandler conversationHandler,
|
||||||
|
MessageUpdatedHandler messageUpdatedHandler) {
|
||||||
ctx = context;
|
ctx = context;
|
||||||
intro = introductionHandler;
|
handler = conversationHandler;
|
||||||
|
msgUpdated = messageUpdatedHandler;
|
||||||
|
setHasStableIds(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContactName(String contactName) {
|
public void setContactName(String contactName) {
|
||||||
@@ -59,82 +62,99 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
return getItem(position).getType();
|
ConversationItem m = getItem(position);
|
||||||
|
if (m instanceof IncomingItem) {
|
||||||
|
if (m instanceof ConversationMessageItem) {
|
||||||
|
return R.layout.list_item_msg_in;
|
||||||
|
} else if (m instanceof ConversationIntroductionRequestItem) {
|
||||||
|
return R.layout.list_item_introduction_in;
|
||||||
|
} else if (m instanceof ConversationIntroductionResponseItem) {
|
||||||
|
return R.layout.list_item_notice_in;
|
||||||
|
} else if (m instanceof ConversationForumInvitationItem) {
|
||||||
|
return R.layout.list_item_forum_invitation_in;
|
||||||
|
}
|
||||||
|
} else if (m instanceof OutgoingItem) {
|
||||||
|
if (m instanceof ConversationMessageItem) {
|
||||||
|
return R.layout.list_item_msg_out;
|
||||||
|
} else if (m instanceof ConversationIntroductionRequestItem) {
|
||||||
|
return R.layout.list_item_introduction_out;
|
||||||
|
} else if (m instanceof ConversationIntroductionResponseItem) {
|
||||||
|
return R.layout.list_item_notice_out;
|
||||||
|
} else if (m instanceof ConversationForumInvitationItem) {
|
||||||
|
return R.layout.list_item_forum_invitation_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Unhandled Conversation Message");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
|
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
|
||||||
View v;
|
View v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
||||||
|
type, viewGroup, false);
|
||||||
|
|
||||||
// outgoing message (local)
|
switch (type) {
|
||||||
if (type == MSG_OUT) {
|
case R.layout.list_item_msg_in:
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
return new MessageHolder(v, false);
|
||||||
R.layout.list_item_msg_out, viewGroup, false);
|
case R.layout.list_item_msg_out:
|
||||||
return new MessageHolder(v, type);
|
return new MessageHolder(v, true);
|
||||||
} else if (type == INTRODUCTION_IN) {
|
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
case R.layout.list_item_introduction_in:
|
||||||
R.layout.list_item_introduction_in, viewGroup, false);
|
return new IntroductionHolder(v, false);
|
||||||
return new IntroductionHolder(v, type);
|
case R.layout.list_item_introduction_out:
|
||||||
} else if (type == INTRODUCTION_OUT) {
|
return new IntroductionHolder(v, true);
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
|
||||||
R.layout.list_item_introduction_out, viewGroup, false);
|
case R.layout.list_item_notice_in:
|
||||||
return new IntroductionHolder(v, type);
|
return new NoticeHolder(v, false);
|
||||||
} else if (type == NOTICE_IN) {
|
case R.layout.list_item_notice_out:
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
return new NoticeHolder(v, true);
|
||||||
R.layout.list_item_notice_in, viewGroup, false);
|
|
||||||
return new NoticeHolder(v, type);
|
case R.layout.list_item_forum_invitation_in:
|
||||||
} else if (type == NOTICE_OUT) {
|
return new InvitationHolder(v, false);
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
case R.layout.list_item_forum_invitation_out:
|
||||||
R.layout.list_item_notice_out, viewGroup, false);
|
return new InvitationHolder(v, true);
|
||||||
return new NoticeHolder(v, type);
|
|
||||||
} else if (type == FORUM_INVITATION_IN) {
|
default:
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
throw new IllegalArgumentException(
|
||||||
R.layout.list_item_forum_invitation_in, viewGroup, false);
|
"Unhandled Conversation Message");
|
||||||
return new InvitationHolder(v, type);
|
|
||||||
} else if (type == FORUM_INVITATION_OUT) {
|
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
|
||||||
R.layout.list_item_forum_invitation_out, viewGroup, false);
|
|
||||||
return new InvitationHolder(v, type);
|
|
||||||
}
|
|
||||||
// incoming message (non-local)
|
|
||||||
else {
|
|
||||||
v = LayoutInflater.from(viewGroup.getContext()).inflate(
|
|
||||||
R.layout.list_item_msg_in, viewGroup, false);
|
|
||||||
return new MessageHolder(v, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ViewHolder ui, int position) {
|
public void onBindViewHolder(ViewHolder ui, int position) {
|
||||||
ConversationItem item = getItem(position);
|
switch (ui.getItemViewType()) {
|
||||||
if (item instanceof ConversationMessageItem) {
|
case R.layout.list_item_msg_in:
|
||||||
bindMessage((MessageHolder) ui, (ConversationMessageItem) item);
|
case R.layout.list_item_msg_out:
|
||||||
} else if (item instanceof ConversationIntroductionOutItem) {
|
bindMessage((MessageHolder) ui, position);
|
||||||
bindIntroduction((IntroductionHolder) ui,
|
break;
|
||||||
(ConversationIntroductionOutItem) item, position);
|
|
||||||
} else if (item instanceof ConversationIntroductionInItem) {
|
case R.layout.list_item_introduction_in:
|
||||||
bindIntroduction((IntroductionHolder) ui,
|
case R.layout.list_item_introduction_out:
|
||||||
(ConversationIntroductionInItem) item, position);
|
bindIntroduction((IntroductionHolder) ui, position);
|
||||||
} else if (item instanceof ConversationNoticeOutItem) {
|
break;
|
||||||
bindNotice((NoticeHolder) ui, (ConversationNoticeOutItem) item);
|
|
||||||
} else if (item instanceof ConversationNoticeInItem) {
|
case R.layout.list_item_notice_in:
|
||||||
bindNotice((NoticeHolder) ui, (ConversationNoticeInItem) item);
|
case R.layout.list_item_notice_out:
|
||||||
} else if (item instanceof ConversationForumInvitationOutItem) {
|
bindNotice((NoticeHolder) ui, position);
|
||||||
bindInvitation((InvitationHolder) ui,
|
break;
|
||||||
(ConversationForumInvitationOutItem) item);
|
|
||||||
} else if (item instanceof ConversationForumInvitationInItem) {
|
case R.layout.list_item_forum_invitation_in:
|
||||||
bindInvitation((InvitationHolder) ui,
|
case R.layout.list_item_forum_invitation_out:
|
||||||
(ConversationForumInvitationInItem) item);
|
bindInvitation((InvitationHolder) ui, position);
|
||||||
} else {
|
break;
|
||||||
throw new IllegalArgumentException("Unhandled Conversation Item");
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unhandled Conversation Message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindMessage(MessageHolder ui, ConversationMessageItem item) {
|
private void bindMessage(final MessageHolder ui, int position) {
|
||||||
|
|
||||||
|
ConversationMessageItem item =
|
||||||
|
(ConversationMessageItem) getItem(position);
|
||||||
PrivateMessageHeader header = item.getHeader();
|
PrivateMessageHeader header = item.getHeader();
|
||||||
|
|
||||||
if (item instanceof ConversationItem.OutgoingItem) {
|
if (item instanceof OutgoingItem) {
|
||||||
if (((OutgoingItem) item).isSeen()) {
|
if (((OutgoingItem) item).isSeen()) {
|
||||||
ui.status.setImageResource(R.drawable.message_delivered_white);
|
ui.status.setImageResource(R.drawable.message_delivered_white);
|
||||||
} else if (((OutgoingItem) item).isSent()) {
|
} else if (((OutgoingItem) item).isSent()) {
|
||||||
@@ -143,7 +163,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
ui.status.setImageResource(R.drawable.message_stored_white);
|
ui.status.setImageResource(R.drawable.message_stored_white);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (item.getType() == MSG_IN_UNREAD) {
|
if (!((IncomingItem) item).isRead()) {
|
||||||
// TODO implement new unread message highlight according to #232
|
// TODO implement new unread message highlight according to #232
|
||||||
/* int left = ui.layout.getPaddingLeft();
|
/* int left = ui.layout.getPaddingLeft();
|
||||||
int top = ui.layout.getPaddingTop();
|
int top = ui.layout.getPaddingTop();
|
||||||
@@ -162,6 +182,12 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
|
|
||||||
if (item.getBody() == null) {
|
if (item.getBody() == null) {
|
||||||
ui.body.setText("\u2026");
|
ui.body.setText("\u2026");
|
||||||
|
item.setContentListener(new ConversationItem.ContentListener() {
|
||||||
|
@Override
|
||||||
|
public void contentReady() {
|
||||||
|
msgUpdated.messageUpdated(ui.getAdapterPosition());
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (header.getContentType().equals("text/plain")) {
|
} else if (header.getContentType().equals("text/plain")) {
|
||||||
ui.body.setText(
|
ui.body.setText(
|
||||||
StringUtils.trim(StringUtils.fromUtf8(item.getBody())));
|
StringUtils.trim(StringUtils.fromUtf8(item.getBody())));
|
||||||
@@ -173,9 +199,10 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
ui.date.setText(AndroidUtils.formatDate(ctx, timestamp));
|
ui.date.setText(AndroidUtils.formatDate(ctx, timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindIntroduction(IntroductionHolder ui,
|
private void bindIntroduction(IntroductionHolder ui, final int position) {
|
||||||
final ConversationIntroductionItem item, final int position) {
|
|
||||||
|
|
||||||
|
final ConversationIntroductionRequestItem item =
|
||||||
|
(ConversationIntroductionRequestItem) getItem(position);
|
||||||
final IntroductionRequest ir = item.getIntroductionRequest();
|
final IntroductionRequest ir = item.getIntroductionRequest();
|
||||||
|
|
||||||
String message = ir.getMessage();
|
String message = ir.getMessage();
|
||||||
@@ -189,11 +216,10 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Outgoing Introduction Request
|
// Outgoing Introduction Request
|
||||||
if (item instanceof ConversationIntroductionOutItem) {
|
if (item instanceof OutgoingItem) {
|
||||||
ui.text.setText(ctx.getString(R.string.introduction_request_sent,
|
ui.text.setText(ctx.getString(R.string.introduction_request_sent,
|
||||||
contactName, ir.getName()));
|
contactName, ir.getName()));
|
||||||
ConversationIntroductionOutItem i =
|
OutgoingItem i = (OutgoingItem) item;
|
||||||
(ConversationIntroductionOutItem) item;
|
|
||||||
if (i.isSeen()) {
|
if (i.isSeen()) {
|
||||||
ui.status.setImageResource(R.drawable.message_delivered);
|
ui.status.setImageResource(R.drawable.message_delivered);
|
||||||
ui.message.status.setImageResource(
|
ui.message.status.setImageResource(
|
||||||
@@ -239,7 +265,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
ui.acceptButton.setOnClickListener(new View.OnClickListener() {
|
ui.acceptButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
intro.respondToIntroduction(ir.getSessionId(), true);
|
handler.respondToItem(item, true);
|
||||||
item.setAnswered(true);
|
item.setAnswered(true);
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
@@ -249,7 +275,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
ui.declineButton.setOnClickListener(new View.OnClickListener() {
|
ui.declineButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
intro.respondToIntroduction(ir.getSessionId(), false);
|
handler.respondToItem(item, false);
|
||||||
item.setAnswered(true);
|
item.setAnswered(true);
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
@@ -258,13 +284,14 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
ui.date.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
ui.date.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindNotice(NoticeHolder ui, ConversationNoticeItem item) {
|
private void bindNotice(NoticeHolder ui, int position) {
|
||||||
|
ConversationItem item = getItem(position);
|
||||||
|
|
||||||
ui.text.setText(item.getText());
|
ui.text.setText(getNoticeText(item));
|
||||||
ui.date.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
ui.date.setText(AndroidUtils.formatDate(ctx, item.getTime()));
|
||||||
|
|
||||||
if (item instanceof ConversationNoticeOutItem) {
|
if (item instanceof OutgoingItem) {
|
||||||
ConversationNoticeOutItem n = (ConversationNoticeOutItem) item;
|
OutgoingItem n = (OutgoingItem) item;
|
||||||
if (n.isSeen()) {
|
if (n.isSeen()) {
|
||||||
ui.status.setImageResource(R.drawable.message_delivered);
|
ui.status.setImageResource(R.drawable.message_delivered);
|
||||||
} else if (n.isSent()) {
|
} else if (n.isSent()) {
|
||||||
@@ -275,9 +302,49 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindInvitation(InvitationHolder ui,
|
private String getNoticeText(ConversationItem m) {
|
||||||
final ConversationForumInvitationItem item) {
|
if (m instanceof ConversationIntroductionResponseItem) {
|
||||||
|
IntroductionResponse ir =
|
||||||
|
((ConversationIntroductionResponseItem) m)
|
||||||
|
.getIntroductionResponse();
|
||||||
|
|
||||||
|
if (ir.isLocal()) {
|
||||||
|
if (ir.wasAccepted()) {
|
||||||
|
return ctx.getString(
|
||||||
|
R.string.introduction_response_accepted_sent,
|
||||||
|
ir.getName());
|
||||||
|
} else {
|
||||||
|
return ctx.getString(
|
||||||
|
R.string.introduction_response_declined_sent,
|
||||||
|
ir.getName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ir.wasAccepted()) {
|
||||||
|
return ctx.getString(
|
||||||
|
R.string.introduction_response_accepted_received,
|
||||||
|
contactName, ir.getName());
|
||||||
|
} else {
|
||||||
|
if (ir.isIntroducer()) {
|
||||||
|
return ctx.getString(
|
||||||
|
R.string.introduction_response_declined_received,
|
||||||
|
contactName, ir.getName());
|
||||||
|
} else {
|
||||||
|
return ctx.getString(
|
||||||
|
R.string.introduction_response_declined_received_by_introducee,
|
||||||
|
contactName, ir.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unhandled Conversation Message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindInvitation(InvitationHolder ui, int position) {
|
||||||
|
|
||||||
|
ConversationForumInvitationItem item =
|
||||||
|
(ConversationForumInvitationItem) getItem(position);
|
||||||
ForumInvitationMessage fim = item.getForumInvitationMessage();
|
ForumInvitationMessage fim = item.getForumInvitationMessage();
|
||||||
|
|
||||||
String message = fim.getMessage();
|
String message = fim.getMessage();
|
||||||
@@ -291,11 +358,10 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Outgoing Invitation
|
// Outgoing Invitation
|
||||||
if (item instanceof ConversationForumInvitationOutItem) {
|
if (item instanceof OutgoingItem) {
|
||||||
ui.text.setText(ctx.getString(R.string.forum_invitation_sent,
|
ui.text.setText(ctx.getString(R.string.forum_invitation_sent,
|
||||||
fim.getForumName(), contactName));
|
fim.getForumName(), contactName));
|
||||||
ConversationForumInvitationOutItem i =
|
OutgoingItem i = (OutgoingItem) item;
|
||||||
(ConversationForumInvitationOutItem) item;
|
|
||||||
if (i.isSeen()) {
|
if (i.isSeen()) {
|
||||||
ui.status.setImageResource(R.drawable.message_delivered);
|
ui.status.setImageResource(R.drawable.message_delivered);
|
||||||
ui.message.status.setImageResource(
|
ui.message.status.setImageResource(
|
||||||
@@ -338,6 +404,23 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
return items.size();
|
return items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
ConversationItem m = getItem(position);
|
||||||
|
if (m == null) {
|
||||||
|
return NO_ID;
|
||||||
|
}
|
||||||
|
byte[] b = m.getId().getBytes();
|
||||||
|
// Technically this could result in collisions because hashCode is not
|
||||||
|
// guaranteed to be collision-resistant. We could instead use BLAKE2s
|
||||||
|
// with hash output set to 8 bytes, and then convert that to a long.
|
||||||
|
long id = Arrays.hashCode(Arrays.copyOf(b, UniqueId.LENGTH / 2));
|
||||||
|
id <<= 32;
|
||||||
|
id |= Arrays.hashCode(
|
||||||
|
Arrays.copyOfRange(b, UniqueId.LENGTH / 2, UniqueId.LENGTH));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public ConversationItem getItem(int position) {
|
public ConversationItem getItem(int position) {
|
||||||
if (position == INVALID_POSITION || items.size() <= position) {
|
if (position == INVALID_POSITION || items.size() <= position) {
|
||||||
return null; // Not found
|
return null; // Not found
|
||||||
@@ -354,7 +437,8 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SparseArray<IncomingItem> getIncomingMessages() {
|
public SparseArray<IncomingItem> getIncomingMessages() {
|
||||||
SparseArray<IncomingItem> messages = new SparseArray<>();
|
SparseArray<IncomingItem> messages =
|
||||||
|
new SparseArray<>();
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
ConversationItem item = items.get(i);
|
ConversationItem item = items.get(i);
|
||||||
@@ -366,7 +450,8 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SparseArray<OutgoingItem> getOutgoingMessages() {
|
public SparseArray<OutgoingItem> getOutgoingMessages() {
|
||||||
SparseArray<OutgoingItem> messages = new SparseArray<>();
|
SparseArray<OutgoingItem> messages =
|
||||||
|
new SparseArray<>();
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
ConversationItem item = items.get(i);
|
ConversationItem item = items.get(i);
|
||||||
@@ -377,18 +462,6 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SparseArray<ConversationMessageItem> getPrivateMessages() {
|
|
||||||
SparseArray<ConversationMessageItem> messages = new SparseArray<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < items.size(); i++) {
|
|
||||||
ConversationItem item = items.get(i);
|
|
||||||
if (item instanceof ConversationMessageItem) {
|
|
||||||
messages.put(i, (ConversationMessageItem) item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(final ConversationItem message) {
|
public void add(final ConversationItem message) {
|
||||||
this.items.add(message);
|
this.items.add(message);
|
||||||
}
|
}
|
||||||
@@ -408,7 +481,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
public TextView date;
|
public TextView date;
|
||||||
public ImageView status;
|
public ImageView status;
|
||||||
|
|
||||||
public MessageHolder(View v, int type) {
|
public MessageHolder(View v, boolean outgoing) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
||||||
layout = (ViewGroup) v.findViewById(R.id.msgLayout);
|
layout = (ViewGroup) v.findViewById(R.id.msgLayout);
|
||||||
@@ -416,7 +489,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
date = (TextView) v.findViewById(R.id.msgTime);
|
date = (TextView) v.findViewById(R.id.msgTime);
|
||||||
|
|
||||||
// outgoing message (local)
|
// outgoing message (local)
|
||||||
if (type == MSG_OUT) {
|
if (outgoing) {
|
||||||
status = (ImageView) v.findViewById(R.id.msgStatus);
|
status = (ImageView) v.findViewById(R.id.msgStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,18 +505,17 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
private final TextView date;
|
private final TextView date;
|
||||||
private final ImageView status;
|
private final ImageView status;
|
||||||
|
|
||||||
public IntroductionHolder(View v, int type) {
|
public IntroductionHolder(View v, boolean outgoing) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
||||||
messageLayout = v.findViewById(R.id.messageLayout);
|
messageLayout = v.findViewById(R.id.messageLayout);
|
||||||
message = new MessageHolder(messageLayout,
|
message = new MessageHolder(messageLayout, outgoing);
|
||||||
type == INTRODUCTION_IN ? MSG_IN : MSG_OUT);
|
|
||||||
text = (TextView) v.findViewById(R.id.introductionText);
|
text = (TextView) v.findViewById(R.id.introductionText);
|
||||||
acceptButton = (Button) v.findViewById(R.id.acceptButton);
|
acceptButton = (Button) v.findViewById(R.id.acceptButton);
|
||||||
declineButton = (Button) v.findViewById(R.id.declineButton);
|
declineButton = (Button) v.findViewById(R.id.declineButton);
|
||||||
date = (TextView) v.findViewById(R.id.introductionTime);
|
date = (TextView) v.findViewById(R.id.introductionTime);
|
||||||
|
|
||||||
if (type == INTRODUCTION_OUT) {
|
if (outgoing) {
|
||||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||||
} else {
|
} else {
|
||||||
status = null;
|
status = null;
|
||||||
@@ -457,13 +529,13 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
private final TextView date;
|
private final TextView date;
|
||||||
private final ImageView status;
|
private final ImageView status;
|
||||||
|
|
||||||
public NoticeHolder(View v, int type) {
|
public NoticeHolder(View v, boolean outgoing) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
||||||
text = (TextView) v.findViewById(R.id.noticeText);
|
text = (TextView) v.findViewById(R.id.noticeText);
|
||||||
date = (TextView) v.findViewById(R.id.noticeTime);
|
date = (TextView) v.findViewById(R.id.noticeTime);
|
||||||
|
|
||||||
if (type == NOTICE_OUT) {
|
if (outgoing) {
|
||||||
status = (ImageView) v.findViewById(R.id.noticeStatus);
|
status = (ImageView) v.findViewById(R.id.noticeStatus);
|
||||||
} else {
|
} else {
|
||||||
status = null;
|
status = null;
|
||||||
@@ -480,17 +552,16 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
private final TextView date;
|
private final TextView date;
|
||||||
private final ImageView status;
|
private final ImageView status;
|
||||||
|
|
||||||
public InvitationHolder(View v, int type) {
|
public InvitationHolder(View v, boolean outgoing) {
|
||||||
super(v);
|
super(v);
|
||||||
|
|
||||||
messageLayout = v.findViewById(R.id.messageLayout);
|
messageLayout = v.findViewById(R.id.messageLayout);
|
||||||
message = new MessageHolder(messageLayout,
|
message = new MessageHolder(messageLayout, outgoing);
|
||||||
type == FORUM_INVITATION_IN ? MSG_IN : MSG_OUT);
|
|
||||||
text = (TextView) v.findViewById(R.id.introductionText);
|
text = (TextView) v.findViewById(R.id.introductionText);
|
||||||
showForumsButton = (Button) v.findViewById(R.id.showForumsButton);
|
showForumsButton = (Button) v.findViewById(R.id.showForumsButton);
|
||||||
date = (TextView) v.findViewById(R.id.introductionTime);
|
date = (TextView) v.findViewById(R.id.introductionTime);
|
||||||
|
|
||||||
if (type == FORUM_INVITATION_OUT) {
|
if (outgoing) {
|
||||||
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
status = (ImageView) v.findViewById(R.id.introductionStatus);
|
||||||
} else {
|
} else {
|
||||||
status = null;
|
status = null;
|
||||||
@@ -498,7 +569,8 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ListCallbacks extends SortedList.Callback<ConversationItem> {
|
private class ListCallbacks
|
||||||
|
extends SortedList.Callback<ConversationItem> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInserted(int position, int count) {
|
public void onInserted(int position, int count) {
|
||||||
@@ -543,7 +615,11 @@ class ConversationAdapter extends RecyclerView.Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IntroductionHandler {
|
public interface ConversationHandler {
|
||||||
void respondToIntroduction(SessionId sessionId, boolean accept);
|
void respondToItem(ConversationItem item, boolean accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MessageUpdatedHandler {
|
||||||
|
void messageUpdated(int position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import org.briarproject.android.controller.ActivityLifecycleController;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConversationController extends ActivityLifecycleController {
|
||||||
|
|
||||||
|
void loadConversation(GroupId groupId,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void loadMessages(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void createMessage(byte[] body, long timestamp,
|
||||||
|
UiResultHandler<ConversationItem> resultHandler);
|
||||||
|
|
||||||
|
ContactId getContactId();
|
||||||
|
|
||||||
|
String getContactName();
|
||||||
|
|
||||||
|
byte[] getContactIdenticonKey();
|
||||||
|
|
||||||
|
List<ConversationItem> getConversationItems();
|
||||||
|
|
||||||
|
boolean isConnected();
|
||||||
|
|
||||||
|
void markMessagesRead(Collection<ConversationItem> unread,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void markNewMessageRead(ConversationItem item);
|
||||||
|
|
||||||
|
void removeContact(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void respondToItem(ConversationItem item, boolean accept, long minTimestamp,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void shouldHideIntroductionAction(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
interface ConversationListener {
|
||||||
|
void contactUpdated();
|
||||||
|
|
||||||
|
void markMessages(Collection<MessageId> messageIds, boolean sent,
|
||||||
|
boolean seen);
|
||||||
|
|
||||||
|
void messageReceived(ConversationItem item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,408 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import org.briarproject.android.controller.DbControllerImpl;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.contact.ContactManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.api.crypto.CryptoExecutor;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.db.NoSuchContactException;
|
||||||
|
import org.briarproject.api.event.ContactConnectedEvent;
|
||||||
|
import org.briarproject.api.event.ContactDisconnectedEvent;
|
||||||
|
import org.briarproject.api.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
||||||
|
import org.briarproject.api.event.Event;
|
||||||
|
import org.briarproject.api.event.EventBus;
|
||||||
|
import org.briarproject.api.event.EventListener;
|
||||||
|
import org.briarproject.api.event.MessagesAckedEvent;
|
||||||
|
import org.briarproject.api.event.MessagesSentEvent;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessage;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessageFactory;
|
||||||
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
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 ConversationControllerImpl extends DbControllerImpl
|
||||||
|
implements ConversationController, EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(ConversationControllerImpl.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected Activity activity;
|
||||||
|
@Inject
|
||||||
|
protected ConnectionRegistry connectionRegistry;
|
||||||
|
@Inject
|
||||||
|
@CryptoExecutor
|
||||||
|
protected Executor cryptoExecutor;
|
||||||
|
|
||||||
|
// Fields that are accessed from background threads must be volatile
|
||||||
|
@Inject
|
||||||
|
protected volatile ContactManager contactManager;
|
||||||
|
@Inject
|
||||||
|
protected volatile ConversationManager conversationManager;
|
||||||
|
@Inject
|
||||||
|
protected volatile EventBus eventBus;
|
||||||
|
@Inject
|
||||||
|
protected volatile PrivateMessageFactory privateMessageFactory;
|
||||||
|
@Inject
|
||||||
|
protected ConversationPersistentData data;
|
||||||
|
|
||||||
|
private ConversationListener listener;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConversationControllerImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreate() {
|
||||||
|
if (activity instanceof ConversationListener) {
|
||||||
|
listener = (ConversationListener) activity;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"An activity that injects the ConversationController " +
|
||||||
|
"must implement the ConversationListener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResume() {
|
||||||
|
eventBus.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityPause() {
|
||||||
|
eventBus.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityDestroy() {
|
||||||
|
if (activity.isFinishing()) {
|
||||||
|
data.clearAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadConversation(final GroupId groupId,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (data.getGroupId() == null ||
|
||||||
|
!data.getGroupId().equals(groupId)) {
|
||||||
|
data.setGroupId(groupId);
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
ContactId contactId =
|
||||||
|
conversationManager.getContactId(groupId);
|
||||||
|
data.setContact(contactManager.getContact(contactId));
|
||||||
|
data.setConnected(
|
||||||
|
connectionRegistry.isConnected(contactId));
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(
|
||||||
|
"Loading contact took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (NoSuchContactException e) {
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMessages(final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
data.addConversationItems(
|
||||||
|
conversationManager
|
||||||
|
.getMessages(getContactId()));
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(
|
||||||
|
"Loading headers took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (NoSuchContactException e) {
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMessage(final byte[] body, final long timestamp,
|
||||||
|
final UiResultHandler<ConversationItem> resultHandler) {
|
||||||
|
cryptoExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
PrivateMessage m = privateMessageFactory
|
||||||
|
.createPrivateMessage(data.getGroupId(), timestamp,
|
||||||
|
null, "text/plain", body);
|
||||||
|
storeMessage(m, body, resultHandler);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// TODO why was this being thrown?
|
||||||
|
//throw new RuntimeException(e);
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeMessage(final PrivateMessage m, final byte[] body,
|
||||||
|
final UiResultHandler<ConversationItem> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
ConversationItem item =
|
||||||
|
conversationManager.addLocalMessage(m, body);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Storing message took " + duration + " ms");
|
||||||
|
resultHandler.onResult(item);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return data.getContact() == null ? null : data.getContact().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContactName() {
|
||||||
|
return data.getContact() == null ? null :
|
||||||
|
data.getContact().getAuthor().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getContactIdenticonKey() {
|
||||||
|
return data.getContact() == null ? null :
|
||||||
|
data.getContact().getAuthor().getId().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConversationItem> getConversationItems() {
|
||||||
|
return data.getConversationItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return data.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markMessagesRead(final Collection<ConversationItem> unread,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
for (ConversationItem item : unread)
|
||||||
|
conversationManager
|
||||||
|
.setReadFlag(getContactId(), item, true);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markNewMessageRead(final ConversationItem item) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
conversationManager
|
||||||
|
.setReadFlag(getContactId(), item, true);
|
||||||
|
}
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeContact(final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
contactManager.removeContact(getContactId());
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respondToItem(final ConversationItem item, final boolean accept,
|
||||||
|
final long minTimestamp,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
timestamp = Math.max(timestamp, minTimestamp);
|
||||||
|
try {
|
||||||
|
conversationManager
|
||||||
|
.respondToItem(getContactId(), item, accept,
|
||||||
|
timestamp);
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException | FormatException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shouldHideIntroductionAction(
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
resultHandler.onResult(
|
||||||
|
contactManager.getActiveContacts().size() < 2);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof ContactRemovedEvent) {
|
||||||
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact removed");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ConversationItemReceivedEvent) {
|
||||||
|
final ConversationItemReceivedEvent event =
|
||||||
|
(ConversationItemReceivedEvent) e;
|
||||||
|
if (event.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Message received, adding");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.messageReceived(event.getItem());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof MessagesSentEvent) {
|
||||||
|
final MessagesSentEvent m = (MessagesSentEvent) e;
|
||||||
|
if (m.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Messages sent");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.markMessages(m.getMessageIds(), true, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof MessagesAckedEvent) {
|
||||||
|
final MessagesAckedEvent m = (MessagesAckedEvent) e;
|
||||||
|
if (m.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Messages acked");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.markMessages(m.getMessageIds(), true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ContactConnectedEvent) {
|
||||||
|
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact connected");
|
||||||
|
data.setConnected(true);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.contactUpdated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
|
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact disconnected");
|
||||||
|
data.setConnected(false);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.contactUpdated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public class ConversationForumInvitationInItem
|
|
||||||
extends ConversationForumInvitationItem
|
|
||||||
implements ConversationItem.IncomingItem {
|
|
||||||
|
|
||||||
private boolean read;
|
|
||||||
|
|
||||||
public ConversationForumInvitationInItem(ForumInvitationMessage fim) {
|
|
||||||
super(fim);
|
|
||||||
|
|
||||||
this.read = fim.isRead();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return FORUM_INVITATION_IN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRead() {
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRead(boolean read) {
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
|
|
||||||
abstract class ConversationForumInvitationItem extends ConversationItem {
|
|
||||||
|
|
||||||
private final ForumInvitationMessage fim;
|
|
||||||
|
|
||||||
public ConversationForumInvitationItem(ForumInvitationMessage fim) {
|
|
||||||
super(fim.getId(), fim.getTimestamp());
|
|
||||||
|
|
||||||
this.fim = fim;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ForumInvitationMessage getForumInvitationMessage() {
|
|
||||||
return fim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is needed and can not be replaced by an ConversationNoticeOutItem,
|
|
||||||
* because it carries the optional invitation message
|
|
||||||
* to be displayed as a regular private message.
|
|
||||||
* <p/>
|
|
||||||
* This class is not thread-safe
|
|
||||||
*/
|
|
||||||
public class ConversationForumInvitationOutItem
|
|
||||||
extends ConversationForumInvitationItem
|
|
||||||
implements ConversationItem.OutgoingItem {
|
|
||||||
|
|
||||||
private boolean sent, seen;
|
|
||||||
|
|
||||||
public ConversationForumInvitationOutItem(ForumInvitationMessage fim) {
|
|
||||||
super(fim);
|
|
||||||
this.sent = fim.isSent();
|
|
||||||
this.seen = fim.isSeen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return FORUM_INVITATION_OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSent() {
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSent(boolean sent) {
|
|
||||||
this.sent = sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeen() {
|
|
||||||
return seen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSeen(boolean seen) {
|
|
||||||
this.seen = seen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public class ConversationIntroductionInItem extends ConversationIntroductionItem
|
|
||||||
implements ConversationItem.IncomingItem {
|
|
||||||
|
|
||||||
private boolean read;
|
|
||||||
|
|
||||||
public ConversationIntroductionInItem(IntroductionRequest ir) {
|
|
||||||
super(ir);
|
|
||||||
|
|
||||||
this.read = ir.isRead();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return INTRODUCTION_IN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRead() {
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRead(boolean read) {
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
abstract class ConversationIntroductionItem extends ConversationItem {
|
|
||||||
|
|
||||||
private final IntroductionRequest ir;
|
|
||||||
private boolean answered;
|
|
||||||
|
|
||||||
public ConversationIntroductionItem(IntroductionRequest ir) {
|
|
||||||
super(ir.getMessageId(), ir.getTimestamp());
|
|
||||||
|
|
||||||
this.ir = ir;
|
|
||||||
this.answered = ir.wasAnswered();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntroductionRequest getIntroductionRequest() {
|
|
||||||
return ir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean wasAnswered() {
|
|
||||||
return answered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAnswered(boolean answered) {
|
|
||||||
this.answered = answered;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is needed and can not be replaced by an ConversationNoticeOutItem,
|
|
||||||
* because it carries the optional introduction message
|
|
||||||
* to be displayed as a regular private message.
|
|
||||||
*
|
|
||||||
* This class is not thread-safe
|
|
||||||
*/
|
|
||||||
public class ConversationIntroductionOutItem
|
|
||||||
extends ConversationIntroductionItem
|
|
||||||
implements ConversationItem.OutgoingItem {
|
|
||||||
|
|
||||||
private boolean sent, seen;
|
|
||||||
|
|
||||||
public ConversationIntroductionOutItem(IntroductionRequest ir) {
|
|
||||||
super(ir);
|
|
||||||
this.sent = ir.isSent();
|
|
||||||
this.seen = ir.isSeen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return INTRODUCTION_OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSent() {
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSent(boolean sent) {
|
|
||||||
this.sent = sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeen() {
|
|
||||||
return seen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSeen(boolean seen) {
|
|
||||||
this.seen = seen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.briarproject.R;
|
|
||||||
import org.briarproject.api.forum.ForumInvitationMessage;
|
|
||||||
import org.briarproject.api.introduction.IntroductionMessage;
|
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
|
||||||
import org.briarproject.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
|
||||||
import org.briarproject.api.sync.MessageId;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public abstract class ConversationItem {
|
|
||||||
|
|
||||||
// this is needed for RecyclerView adapter which requires an int type
|
|
||||||
final static int MSG_IN = 0;
|
|
||||||
final static int MSG_IN_UNREAD = 1;
|
|
||||||
final static int MSG_OUT = 2;
|
|
||||||
final static int INTRODUCTION_IN = 3;
|
|
||||||
final static int INTRODUCTION_OUT = 4;
|
|
||||||
final static int NOTICE_IN = 5;
|
|
||||||
final static int NOTICE_OUT = 6;
|
|
||||||
final static int FORUM_INVITATION_IN = 7;
|
|
||||||
final static int FORUM_INVITATION_OUT = 8;
|
|
||||||
|
|
||||||
private MessageId id;
|
|
||||||
private long time;
|
|
||||||
|
|
||||||
public ConversationItem(MessageId id, long time) {
|
|
||||||
this.id = id;
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract int getType();
|
|
||||||
|
|
||||||
public MessageId getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
long getTime() {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConversationItem from(PrivateMessageHeader h) {
|
|
||||||
if (h.isLocal())
|
|
||||||
return new ConversationMessageOutItem(h);
|
|
||||||
else
|
|
||||||
return new ConversationMessageInItem(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConversationItem from(IntroductionRequest ir) {
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
return new ConversationIntroductionOutItem(ir);
|
|
||||||
} else {
|
|
||||||
return new ConversationIntroductionInItem(ir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConversationItem from(Context ctx, String contactName,
|
|
||||||
IntroductionResponse ir) {
|
|
||||||
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
String text;
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_accepted_sent,
|
|
||||||
ir.getName());
|
|
||||||
} else {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_sent,
|
|
||||||
ir.getName());
|
|
||||||
}
|
|
||||||
return new ConversationNoticeOutItem(ir.getMessageId(), text,
|
|
||||||
ir.getTimestamp(), ir.isSent(), ir.isSeen());
|
|
||||||
} else {
|
|
||||||
String text;
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_accepted_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else {
|
|
||||||
if (ir.isIntroducer()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_received_by_introducee,
|
|
||||||
contactName, ir.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ConversationNoticeInItem(ir.getMessageId(), text,
|
|
||||||
ir.getTimestamp(), ir.isRead());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConversationItem from(ForumInvitationMessage fim) {
|
|
||||||
if (fim.isLocal()) {
|
|
||||||
return new ConversationForumInvitationOutItem(fim);
|
|
||||||
} else {
|
|
||||||
return new ConversationForumInvitationInItem(fim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method should not be used to get user-facing objects,
|
|
||||||
* Its purpose is to provider data for the contact list.
|
|
||||||
*/
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected interface OutgoingItem {
|
|
||||||
|
|
||||||
MessageId getId();
|
|
||||||
|
|
||||||
boolean isSent();
|
|
||||||
|
|
||||||
void setSent(boolean sent);
|
|
||||||
|
|
||||||
boolean isSeen();
|
|
||||||
|
|
||||||
void setSeen(boolean seen);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected interface IncomingItem {
|
|
||||||
|
|
||||||
MessageId getId();
|
|
||||||
|
|
||||||
boolean isRead();
|
|
||||||
|
|
||||||
void setRead(boolean read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public class ConversationMessageInItem extends ConversationMessageItem
|
|
||||||
implements ConversationItem.IncomingItem {
|
|
||||||
|
|
||||||
private boolean read;
|
|
||||||
|
|
||||||
public ConversationMessageInItem(PrivateMessageHeader header) {
|
|
||||||
super(header);
|
|
||||||
|
|
||||||
read = header.isRead();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return MSG_IN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRead() {
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRead(boolean read) {
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
abstract class ConversationMessageItem extends ConversationItem {
|
|
||||||
|
|
||||||
private final PrivateMessageHeader header;
|
|
||||||
private byte[] body;
|
|
||||||
|
|
||||||
public ConversationMessageItem(PrivateMessageHeader header) {
|
|
||||||
super(header.getId(), header.getTimestamp());
|
|
||||||
|
|
||||||
this.header = header;
|
|
||||||
body = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrivateMessageHeader getHeader() {
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] getBody() {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBody(byte[] body) {
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public class ConversationMessageOutItem extends ConversationMessageItem
|
|
||||||
implements ConversationItem.OutgoingItem {
|
|
||||||
|
|
||||||
private boolean sent, seen;
|
|
||||||
|
|
||||||
public ConversationMessageOutItem(PrivateMessageHeader header) {
|
|
||||||
super(header);
|
|
||||||
|
|
||||||
sent = header.isSent();
|
|
||||||
seen = header.isSeen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return MSG_OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSent() {
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSent(boolean sent) {
|
|
||||||
this.sent = sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSeen() {
|
|
||||||
return seen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSeen(boolean seen) {
|
|
||||||
this.seen = seen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.sync.MessageId;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
|
||||||
public class ConversationNoticeInItem extends ConversationNoticeItem
|
|
||||||
implements ConversationItem.IncomingItem {
|
|
||||||
|
|
||||||
private boolean read;
|
|
||||||
|
|
||||||
public ConversationNoticeInItem(MessageId id, String text, long time,
|
|
||||||
boolean read) {
|
|
||||||
super(id, text, time);
|
|
||||||
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getType() {
|
|
||||||
return NOTICE_IN;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRead() {
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRead(boolean read) {
|
|
||||||
this.read = read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package org.briarproject.android.contact;
|
|
||||||
|
|
||||||
import org.briarproject.api.sync.MessageId;
|
|
||||||
|
|
||||||
abstract class ConversationNoticeItem extends ConversationItem {
|
|
||||||
|
|
||||||
private final String text;
|
|
||||||
|
|
||||||
public ConversationNoticeItem(MessageId id, String text, long time) {
|
|
||||||
super(id, time);
|
|
||||||
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a singleton that defines the data that should persist, i.e.
|
||||||
|
* still be present in memory after activity restarts. This class is not thread
|
||||||
|
* safe.
|
||||||
|
*/
|
||||||
|
public class ConversationPersistentData {
|
||||||
|
|
||||||
|
private volatile GroupId groupId;
|
||||||
|
private volatile Contact contact;
|
||||||
|
private volatile boolean connected;
|
||||||
|
private volatile List<ConversationItem> items = new ArrayList<>();
|
||||||
|
|
||||||
|
public void clearAll() {
|
||||||
|
groupId = null;
|
||||||
|
contact = null;
|
||||||
|
connected = false;
|
||||||
|
items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupId getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupId(GroupId groupId) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contact getContact() {
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContact(Contact contact) {
|
||||||
|
this.contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnected(boolean connected) {
|
||||||
|
this.connected = connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConversationItems(Collection<ConversationItem> items) {
|
||||||
|
this.items.addAll(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConversationItem> getConversationItems() {
|
||||||
|
return Collections.unmodifiableList(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
|||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
ContactListItem item =
|
ContactListItem item =
|
||||||
new ContactListItem(c, localAuthor, false, null,
|
new ContactListItem(c, localAuthor, false, null,
|
||||||
null);
|
-1, 0);
|
||||||
contactItems.add(item);
|
contactItems.add(item);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -141,7 +141,7 @@ public class ForumSharingStatusActivity extends BriarActivity {
|
|||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
ContactListItem item =
|
ContactListItem item =
|
||||||
new ContactListItem(c, localAuthor, false, null,
|
new ContactListItem(c, localAuthor, false, null,
|
||||||
null);
|
-1, 0);
|
||||||
contactItems.add(item);
|
contactItems.add(item);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package org.briarproject.android.forum;
|
package org.briarproject.android.forum;
|
||||||
|
|
||||||
import org.briarproject.android.contact.ContactListItem;
|
import org.briarproject.android.contact.ContactListItem;
|
||||||
import org.briarproject.android.contact.ConversationItem;
|
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
import org.briarproject.api.identity.LocalAuthor;
|
import org.briarproject.api.identity.LocalAuthor;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
@@ -16,8 +16,7 @@ public class SelectableContactListItem extends ContactListItem {
|
|||||||
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
|
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
|
||||||
GroupId groupId, boolean selected, boolean disabled) {
|
GroupId groupId, boolean selected, boolean disabled) {
|
||||||
|
|
||||||
super(contact, localAuthor, false, groupId,
|
super(contact, localAuthor, false, groupId, -1, 0);
|
||||||
Collections.<ConversationItem>emptyList());
|
|
||||||
|
|
||||||
this.selected = selected;
|
this.selected = selected;
|
||||||
this.disabled = disabled;
|
this.disabled = disabled;
|
||||||
|
|||||||
@@ -15,20 +15,17 @@ import org.briarproject.R;
|
|||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.contact.ContactListAdapter;
|
import org.briarproject.android.contact.ContactListAdapter;
|
||||||
import org.briarproject.android.contact.ContactListItem;
|
import org.briarproject.android.contact.ContactListItem;
|
||||||
import org.briarproject.android.contact.ConversationItem;
|
|
||||||
import org.briarproject.android.fragment.BaseFragment;
|
import org.briarproject.android.fragment.BaseFragment;
|
||||||
import org.briarproject.android.util.BriarRecyclerView;
|
import org.briarproject.android.util.BriarRecyclerView;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
import org.briarproject.api.contact.ContactManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.identity.AuthorId;
|
import org.briarproject.api.identity.AuthorId;
|
||||||
import org.briarproject.api.identity.IdentityManager;
|
import org.briarproject.api.identity.IdentityManager;
|
||||||
import org.briarproject.api.identity.LocalAuthor;
|
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.plugins.ConnectionRegistry;
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
@@ -61,9 +58,7 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
@Inject
|
@Inject
|
||||||
protected volatile IdentityManager identityManager;
|
protected volatile IdentityManager identityManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile MessagingManager messagingManager;
|
protected volatile ConversationManager conversationManager;
|
||||||
@Inject
|
|
||||||
protected volatile IntroductionManager introductionManager;
|
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ConnectionRegistry connectionRegistry;
|
protected volatile ConnectionRegistry connectionRegistry;
|
||||||
|
|
||||||
@@ -166,15 +161,19 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
} else {
|
} else {
|
||||||
ContactId id = c.getId();
|
ContactId id = c.getId();
|
||||||
GroupId groupId =
|
GroupId groupId =
|
||||||
messagingManager.getConversationId(id);
|
conversationManager.getConversationId(id);
|
||||||
Collection<ConversationItem> messages =
|
|
||||||
getMessages(id);
|
|
||||||
boolean connected =
|
boolean connected =
|
||||||
connectionRegistry.isConnected(c.getId());
|
connectionRegistry.isConnected(c.getId());
|
||||||
LocalAuthor localAuthor = identityManager
|
LocalAuthor localAuthor = identityManager
|
||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
|
long timestamp = conversationManager.getTimestamp(id);
|
||||||
|
long now1 = System.currentTimeMillis();
|
||||||
|
int unread = conversationManager.getUnreadCount(id);
|
||||||
|
long duration = System.currentTimeMillis() - now1;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Loading unread messages took " + duration + " ms");
|
||||||
contacts.add(new ContactListItem(c, localAuthor,
|
contacts.add(new ContactListItem(c, localAuthor,
|
||||||
connected, groupId, messages));
|
connected, groupId, timestamp, unread));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayContacts(localAuthorId, contacts);
|
displayContacts(localAuthorId, contacts);
|
||||||
@@ -218,37 +217,4 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
builder.setNegativeButton(android.R.string.cancel, null);
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
builder.show();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.api.db.DbException;
|
|||||||
import org.briarproject.api.sharing.SharingManager;
|
import org.briarproject.api.sharing.SharingManager;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -37,6 +38,13 @@ public interface BlogSharingManager
|
|||||||
Collection<BlogInvitationMessage> getInvitationMessages(
|
Collection<BlogInvitationMessage> getInvitationMessages(
|
||||||
ContactId contactId) throws DbException;
|
ContactId contactId) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific blog sharing message sent by the Contact
|
||||||
|
* identified by contactId.
|
||||||
|
*/
|
||||||
|
BlogInvitationMessage getInvitationMessage(ContactId contactId,
|
||||||
|
MessageId messageId) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all blogs to which the user has been invited.
|
* Returns all blogs to which the user has been invited.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.briarproject.api.clients;
|
||||||
|
|
||||||
|
public interface ReadableMessageConstants {
|
||||||
|
|
||||||
|
/* Readable Message Local State Metadata */
|
||||||
|
String LOCAL = "local";
|
||||||
|
String READ = "read";
|
||||||
|
String TIMESTAMP = "timestamp";
|
||||||
|
String UNREAD = "unread";
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.briarproject.api.clients;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
public interface ReadableMessageManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timestamp of the latest message in the group with the given
|
||||||
|
* contact, or -1 if the group is empty.
|
||||||
|
*/
|
||||||
|
long getTimestamp(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of unread messages in the group with the given
|
||||||
|
* contact.
|
||||||
|
*/
|
||||||
|
int getUnreadCount(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a message as read or unread.
|
||||||
|
*/
|
||||||
|
void setReadFlag(ContactId c, MessageId m, boolean local, boolean read)
|
||||||
|
throws DbException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||||
|
|
||||||
|
public interface ConversationForumInvitationItem extends ConversationItem {
|
||||||
|
|
||||||
|
ForumInvitationMessage getForumInvitationMessage();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.introduction.IntroductionRequest;
|
||||||
|
|
||||||
|
public interface ConversationIntroductionRequestItem extends ConversationItem {
|
||||||
|
|
||||||
|
IntroductionRequest getIntroductionRequest();
|
||||||
|
|
||||||
|
boolean wasAnswered();
|
||||||
|
|
||||||
|
void setAnswered(boolean answered);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.introduction.IntroductionResponse;
|
||||||
|
|
||||||
|
public interface ConversationIntroductionResponseItem extends ConversationItem {
|
||||||
|
|
||||||
|
IntroductionResponse getIntroductionResponse();
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
public interface ConversationItem {
|
||||||
|
|
||||||
|
MessageId getId();
|
||||||
|
|
||||||
|
long getTime();
|
||||||
|
|
||||||
|
interface ContentListener {
|
||||||
|
|
||||||
|
void contentReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Partial extends ConversationItem {
|
||||||
|
|
||||||
|
void setContent(byte[] content);
|
||||||
|
|
||||||
|
void setContentListener(ContentListener listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IncomingItem extends ConversationItem {
|
||||||
|
|
||||||
|
boolean isRead();
|
||||||
|
|
||||||
|
void setRead(boolean read);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OutgoingItem extends ConversationItem {
|
||||||
|
|
||||||
|
boolean isSent();
|
||||||
|
|
||||||
|
void setSent(boolean sent);
|
||||||
|
|
||||||
|
boolean isSeen();
|
||||||
|
|
||||||
|
void setSeen(boolean seen);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessage;
|
||||||
|
import org.briarproject.api.sync.ClientId;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConversationManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique ID of the conversation client.
|
||||||
|
*/
|
||||||
|
ClientId getClientId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a local private message, and returns the corresponding item.
|
||||||
|
*/
|
||||||
|
ConversationItem addLocalMessage(PrivateMessage m, byte[] body) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of the contact with the given private conversation.
|
||||||
|
*/
|
||||||
|
ContactId getContactId(GroupId g) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of the private conversation with the given contact.
|
||||||
|
*/
|
||||||
|
GroupId getConversationId(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all messages in the given private conversation.
|
||||||
|
*/
|
||||||
|
List<ConversationItem> getMessages(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timestamp of the latest message in the given private
|
||||||
|
* conversation, or -1 if the conversation is empty.
|
||||||
|
*/
|
||||||
|
long getTimestamp(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of unread messages in the given private conversation.
|
||||||
|
*/
|
||||||
|
int getUnreadCount(ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a background task to load the content of the given message.
|
||||||
|
*/
|
||||||
|
void loadMessageContent(ConversationItem.Partial m);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a conversation item with accept/decline.
|
||||||
|
*/
|
||||||
|
void respondToItem(ContactId c, ConversationItem item, boolean accept,
|
||||||
|
long timestamp) throws DbException, FormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a conversation item as read or unread.
|
||||||
|
*/
|
||||||
|
void setReadFlag(ContactId c, ConversationItem item, boolean read) throws DbException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.briarproject.api.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.Partial;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||||
|
|
||||||
|
public interface ConversationMessageItem extends Partial {
|
||||||
|
|
||||||
|
PrivateMessageHeader getHeader();
|
||||||
|
|
||||||
|
byte[] getBody();
|
||||||
|
}
|
||||||
@@ -2,13 +2,15 @@ package org.briarproject.api.event;
|
|||||||
|
|
||||||
import org.briarproject.api.blogs.Blog;
|
import org.briarproject.api.blogs.Blog;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
public class BlogInvitationReceivedEvent extends InvitationReceivedEvent {
|
public class BlogInvitationReceivedEvent extends InvitationReceivedEvent {
|
||||||
|
|
||||||
private final Blog blog;
|
private final Blog blog;
|
||||||
|
|
||||||
public BlogInvitationReceivedEvent(Blog blog, ContactId contactId) {
|
public BlogInvitationReceivedEvent(ContactId contactId, MessageId messageId,
|
||||||
super(contactId);
|
Blog blog) {
|
||||||
|
super(contactId, messageId);
|
||||||
this.blog = blog;
|
this.blog = blog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.briarproject.api.event;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when a new conversation item is received.
|
||||||
|
*/
|
||||||
|
public class ConversationItemReceivedEvent extends Event {
|
||||||
|
|
||||||
|
private final ConversationItem item;
|
||||||
|
private final ContactId contactId;
|
||||||
|
|
||||||
|
public ConversationItemReceivedEvent(ConversationItem item,
|
||||||
|
ContactId contactId) {
|
||||||
|
this.item = item;
|
||||||
|
this.contactId = contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationItem getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,15 @@ package org.briarproject.api.event;
|
|||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.forum.Forum;
|
import org.briarproject.api.forum.Forum;
|
||||||
import org.briarproject.api.introduction.IntroductionRequest;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
public class ForumInvitationReceivedEvent extends InvitationReceivedEvent {
|
public class ForumInvitationReceivedEvent extends InvitationReceivedEvent {
|
||||||
|
|
||||||
private final Forum forum;
|
private final Forum forum;
|
||||||
|
|
||||||
public ForumInvitationReceivedEvent(Forum forum, ContactId contactId) {
|
public ForumInvitationReceivedEvent(ContactId contactId,
|
||||||
super(contactId);
|
MessageId messageId, Forum forum) {
|
||||||
|
super(contactId, messageId);
|
||||||
this.forum = forum;
|
this.forum = forum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
package org.briarproject.api.event;
|
package org.briarproject.api.event;
|
||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.forum.Forum;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
public abstract class InvitationReceivedEvent extends Event {
|
public abstract class InvitationReceivedEvent extends Event {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
private final MessageId messageId;
|
||||||
|
|
||||||
public InvitationReceivedEvent(ContactId contactId) {
|
public InvitationReceivedEvent(ContactId contactId, MessageId messageId) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
|
this.messageId = messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MessageId getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.api.db.DbException;
|
|||||||
import org.briarproject.api.sharing.SharingManager;
|
import org.briarproject.api.sharing.SharingManager;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@@ -34,6 +35,13 @@ public interface ForumSharingManager extends SharingManager<Forum, ForumInvitati
|
|||||||
Collection<ForumInvitationMessage> getInvitationMessages(
|
Collection<ForumInvitationMessage> getInvitationMessages(
|
||||||
ContactId contactId) throws DbException;
|
ContactId contactId) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific forum sharing message sent by the Contact
|
||||||
|
* identified by contactId.
|
||||||
|
*/
|
||||||
|
ForumInvitationMessage getInvitationMessage(ContactId contactId,
|
||||||
|
MessageId messageId) throws DbException;
|
||||||
|
|
||||||
/** Returns all forums to which the user has been invited. */
|
/** Returns all forums to which the user has been invited. */
|
||||||
Collection<Forum> getInvited() throws DbException;
|
Collection<Forum> getInvited() throws DbException;
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ public interface IntroductionConstants {
|
|||||||
String CONTACT_ID_2 = "contactId2";
|
String CONTACT_ID_2 = "contactId2";
|
||||||
String RESPONSE_1 = "response1";
|
String RESPONSE_1 = "response1";
|
||||||
String RESPONSE_2 = "response2";
|
String RESPONSE_2 = "response2";
|
||||||
String READ = "read";
|
|
||||||
|
|
||||||
/* Introduction Request Action */
|
/* Introduction Request Action */
|
||||||
String PUBLIC_KEY1 = "publicKey1";
|
String PUBLIC_KEY1 = "publicKey1";
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package org.briarproject.api.introduction;
|
package org.briarproject.api.introduction;
|
||||||
|
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.ReadableMessageManager;
|
||||||
import org.briarproject.api.clients.SessionId;
|
import org.briarproject.api.clients.SessionId;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface IntroductionManager {
|
public interface IntroductionManager extends ReadableMessageManager {
|
||||||
|
|
||||||
/** Returns the unique ID of the introduction client. */
|
/** Returns the unique ID of the introduction client. */
|
||||||
ClientId getClientId();
|
ClientId getClientId();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.api.messaging;
|
package org.briarproject.api.messaging;
|
||||||
|
|
||||||
|
import org.briarproject.api.clients.ReadableMessageManager;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
@@ -8,7 +9,7 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface MessagingManager {
|
public interface MessagingManager extends ReadableMessageManager {
|
||||||
|
|
||||||
/** Returns the unique ID of the messaging client. */
|
/** Returns the unique ID of the messaging client. */
|
||||||
ClientId getClientId();
|
ClientId getClientId();
|
||||||
@@ -30,7 +31,4 @@ public interface MessagingManager {
|
|||||||
|
|
||||||
/** Returns the body of the private message with the given ID. */
|
/** Returns the body of the private message with the given ID. */
|
||||||
byte[] getMessageBody(MessageId m) throws DbException;
|
byte[] getMessageBody(MessageId m) throws DbException;
|
||||||
|
|
||||||
/** Marks a private message as read or unread. */
|
|
||||||
void setReadFlag(MessageId m, boolean read) throws DbException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ public interface SharingConstants {
|
|||||||
String SESSION_ID = "sessionId";
|
String SESSION_ID = "sessionId";
|
||||||
String STORAGE_ID = "storageId";
|
String STORAGE_ID = "storageId";
|
||||||
String STATE = "state";
|
String STATE = "state";
|
||||||
String LOCAL = "local";
|
|
||||||
String TIME = "time";
|
|
||||||
String READ = "read";
|
|
||||||
String IS_SHARER = "isSharer";
|
String IS_SHARER = "isSharer";
|
||||||
String SHAREABLE_ID = "shareableId";
|
String SHAREABLE_ID = "shareableId";
|
||||||
String INVITATION_MSG = "invitationMsg";
|
String INVITATION_MSG = "invitationMsg";
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package org.briarproject.api.sharing;
|
package org.briarproject.api.sharing;
|
||||||
|
|
||||||
|
import org.briarproject.api.clients.ReadableMessageManager;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface SharingManager<S extends Shareable, IM extends InvitationMessage> {
|
public interface SharingManager<S extends Shareable, IM extends InvitationMessage>
|
||||||
|
extends ReadableMessageManager {
|
||||||
|
|
||||||
/** Returns the unique ID of the group sharing client. */
|
/** Returns the unique ID of the group sharing client. */
|
||||||
ClientId getClientId();
|
ClientId getClientId();
|
||||||
@@ -33,6 +36,13 @@ public interface SharingManager<S extends Shareable, IM extends InvitationMessag
|
|||||||
Collection<IM> getInvitationMessages(
|
Collection<IM> getInvitationMessages(
|
||||||
ContactId contactId) throws DbException;
|
ContactId contactId) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a specific group sharing message sent by the Contact
|
||||||
|
* identified by contactId.
|
||||||
|
*/
|
||||||
|
IM getInvitationMessage(ContactId contactId, MessageId messageId)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/** Returns all shareables to which the user has been invited. */
|
/** Returns all shareables to which the user has been invited. */
|
||||||
Collection<S> getInvited() throws DbException;
|
Collection<S> getInvited() throws DbException;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject;
|
|||||||
|
|
||||||
import org.briarproject.blogs.BlogsModule;
|
import org.briarproject.blogs.BlogsModule;
|
||||||
import org.briarproject.contact.ContactModule;
|
import org.briarproject.contact.ContactModule;
|
||||||
|
import org.briarproject.conversation.ConversationModule;
|
||||||
import org.briarproject.crypto.CryptoModule;
|
import org.briarproject.crypto.CryptoModule;
|
||||||
import org.briarproject.db.DatabaseExecutorModule;
|
import org.briarproject.db.DatabaseExecutorModule;
|
||||||
import org.briarproject.forum.ForumModule;
|
import org.briarproject.forum.ForumModule;
|
||||||
@@ -22,6 +23,8 @@ public interface CoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(ContactModule.EagerSingletons init);
|
void inject(ContactModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(ConversationModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(CryptoModule.EagerSingletons init);
|
void inject(CryptoModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(DatabaseExecutorModule.EagerSingletons init);
|
void inject(DatabaseExecutorModule.EagerSingletons init);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject;
|
|||||||
import org.briarproject.blogs.BlogsModule;
|
import org.briarproject.blogs.BlogsModule;
|
||||||
import org.briarproject.clients.ClientsModule;
|
import org.briarproject.clients.ClientsModule;
|
||||||
import org.briarproject.contact.ContactModule;
|
import org.briarproject.contact.ContactModule;
|
||||||
|
import org.briarproject.conversation.ConversationModule;
|
||||||
import org.briarproject.crypto.CryptoModule;
|
import org.briarproject.crypto.CryptoModule;
|
||||||
import org.briarproject.data.DataModule;
|
import org.briarproject.data.DataModule;
|
||||||
import org.briarproject.db.DatabaseExecutorModule;
|
import org.briarproject.db.DatabaseExecutorModule;
|
||||||
@@ -31,6 +32,7 @@ import dagger.Module;
|
|||||||
BlogsModule.class,
|
BlogsModule.class,
|
||||||
ClientsModule.class,
|
ClientsModule.class,
|
||||||
ContactModule.class,
|
ContactModule.class,
|
||||||
|
ConversationModule.class,
|
||||||
CryptoModule.class,
|
CryptoModule.class,
|
||||||
DataModule.class,
|
DataModule.class,
|
||||||
DatabaseModule.class,
|
DatabaseModule.class,
|
||||||
@@ -58,6 +60,7 @@ public class CoreModule {
|
|||||||
public static void initEagerSingletons(CoreEagerSingletons c) {
|
public static void initEagerSingletons(CoreEagerSingletons c) {
|
||||||
c.inject(new BlogsModule.EagerSingletons());
|
c.inject(new BlogsModule.EagerSingletons());
|
||||||
c.inject(new ContactModule.EagerSingletons());
|
c.inject(new ContactModule.EagerSingletons());
|
||||||
|
c.inject(new ConversationModule.EagerSingletons());
|
||||||
c.inject(new CryptoModule.EagerSingletons());
|
c.inject(new CryptoModule.EagerSingletons());
|
||||||
c.inject(new DatabaseExecutorModule.EagerSingletons());
|
c.inject(new DatabaseExecutorModule.EagerSingletons());
|
||||||
c.inject(new ForumModule.EagerSingletons());
|
c.inject(new ForumModule.EagerSingletons());
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package org.briarproject.clients;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.ClientHelper;
|
||||||
|
import org.briarproject.api.clients.ReadableMessageManager;
|
||||||
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.api.data.BdfList;
|
||||||
|
import org.briarproject.api.data.MetadataParser;
|
||||||
|
import org.briarproject.api.db.DatabaseComponent;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.db.Transaction;
|
||||||
|
import org.briarproject.api.sync.Group;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.InvalidMessageException;
|
||||||
|
import org.briarproject.api.sync.Message;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.UNREAD;
|
||||||
|
|
||||||
|
public abstract class ReadableMessageManagerImpl
|
||||||
|
extends BdfIncomingMessageHook implements ReadableMessageManager {
|
||||||
|
|
||||||
|
protected final DatabaseComponent db;
|
||||||
|
|
||||||
|
protected ReadableMessageManagerImpl(ClientHelper clientHelper,
|
||||||
|
DatabaseComponent db, MetadataParser metadataParser) {
|
||||||
|
super(clientHelper, metadataParser);
|
||||||
|
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Group getContactGroup(Contact c);
|
||||||
|
|
||||||
|
protected abstract void incomingReadableMessage(Transaction txn,
|
||||||
|
Message m, BdfList body, BdfDictionary meta)
|
||||||
|
throws DbException, FormatException, InvalidMessageException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
||||||
|
BdfDictionary meta) throws DbException, FormatException {
|
||||||
|
|
||||||
|
// Check if we accept this message
|
||||||
|
try {
|
||||||
|
incomingReadableMessage(txn, m, body, meta);
|
||||||
|
|
||||||
|
// Update the group timestamp and unread count
|
||||||
|
GroupId groupId = m.getGroupId();
|
||||||
|
long timestamp = meta.getLong(TIMESTAMP);
|
||||||
|
boolean local = meta.getBoolean(LOCAL);
|
||||||
|
boolean read = meta.getBoolean(READ);
|
||||||
|
updateGroupMetadata(txn, groupId, timestamp, local, read, read);
|
||||||
|
} catch (InvalidMessageException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp(ContactId c) throws DbException {
|
||||||
|
BdfDictionary meta;
|
||||||
|
Transaction txn = db.startTransaction(true);
|
||||||
|
try {
|
||||||
|
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
|
||||||
|
meta = clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||||
|
txn.setComplete();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
|
}
|
||||||
|
return meta.getLong(TIMESTAMP, -1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getUnreadCount(ContactId c) throws DbException {
|
||||||
|
BdfDictionary meta;
|
||||||
|
Transaction txn = db.startTransaction(true);
|
||||||
|
try {
|
||||||
|
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
|
||||||
|
meta = clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||||
|
txn.setComplete();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
|
}
|
||||||
|
return meta.getLong(UNREAD, 0L).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadFlag(ContactId c, MessageId m, boolean local,
|
||||||
|
boolean read) throws DbException {
|
||||||
|
Transaction txn = db.startTransaction(false);
|
||||||
|
try {
|
||||||
|
boolean wasRead =
|
||||||
|
clientHelper.getMessageMetadataAsDictionary(txn, m)
|
||||||
|
.getBoolean(READ);
|
||||||
|
BdfDictionary meta = new BdfDictionary();
|
||||||
|
meta.put(READ, read);
|
||||||
|
clientHelper.mergeMessageMetadata(txn, m, meta);
|
||||||
|
updateContactMetadata(txn, c, -1, local, wasRead, read);
|
||||||
|
txn.setComplete();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateContactMetadata(Transaction txn, ContactId contactId,
|
||||||
|
long timestamp, boolean local, boolean wasRead, boolean read)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
GroupId g = getContactGroup(db.getContact(txn, contactId)).getId();
|
||||||
|
updateGroupMetadata(txn, g, timestamp, local, wasRead, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateGroupMetadata(Transaction txn, GroupId groupId,
|
||||||
|
long timestamp, boolean local, boolean wasRead, boolean read)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
BdfDictionary groupMeta =
|
||||||
|
clientHelper.getGroupMetadataAsDictionary(txn, groupId);
|
||||||
|
long groupTimestamp = groupMeta.getLong(TIMESTAMP, -1L);
|
||||||
|
int unread = groupMeta.getLong(UNREAD, 0L).intValue();
|
||||||
|
BdfDictionary d = new BdfDictionary();
|
||||||
|
if (timestamp > groupTimestamp) {
|
||||||
|
d.put(TIMESTAMP, timestamp);
|
||||||
|
}
|
||||||
|
if (!local && (wasRead != read)) {
|
||||||
|
d.put(UNREAD, read ? (unread > 0 ? unread - 1 : 0) : unread + 1);
|
||||||
|
}
|
||||||
|
clientHelper.mergeGroupMetadata(txn, groupId, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationForumInvitationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||||
|
|
||||||
|
class ConversationForumInvitationItemImpl {
|
||||||
|
|
||||||
|
static ConversationItem from(ForumInvitationMessage i) {
|
||||||
|
return i.isLocal() ? new Outgoing(i) : new Incoming(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Outgoing extends OutgoingConversationItem
|
||||||
|
implements ConversationForumInvitationItem {
|
||||||
|
|
||||||
|
private final ForumInvitationMessage fim;
|
||||||
|
|
||||||
|
public Outgoing(ForumInvitationMessage fim) {
|
||||||
|
super(fim.getId(), fim.getTimestamp(), fim.isSent(), fim.isSeen());
|
||||||
|
|
||||||
|
this.fim = fim;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForumInvitationMessage getForumInvitationMessage() {
|
||||||
|
return fim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Incoming extends IncomingConversationItem
|
||||||
|
implements ConversationForumInvitationItem {
|
||||||
|
|
||||||
|
private final ForumInvitationMessage fim;
|
||||||
|
|
||||||
|
public Incoming(ForumInvitationMessage fim) {
|
||||||
|
super(fim.getId(), fim.getTimestamp(), fim.isRead());
|
||||||
|
|
||||||
|
this.fim = fim;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForumInvitationMessage getForumInvitationMessage() {
|
||||||
|
return fim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionRequestItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.introduction.IntroductionRequest;
|
||||||
|
|
||||||
|
class ConversationIntroductionRequestItemImpl {
|
||||||
|
|
||||||
|
static ConversationItem from(IntroductionRequest i) {
|
||||||
|
return i.isLocal() ? new Outgoing(i) : new Incoming(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Outgoing extends OutgoingConversationItem
|
||||||
|
implements ConversationIntroductionRequestItem {
|
||||||
|
|
||||||
|
private final IntroductionRequest ir;
|
||||||
|
private boolean answered;
|
||||||
|
|
||||||
|
public Outgoing(IntroductionRequest ir) {
|
||||||
|
super(ir.getMessageId(), ir.getTimestamp(), ir.isSent(), ir.isSeen());
|
||||||
|
|
||||||
|
this.ir = ir;
|
||||||
|
this.answered = ir.wasAnswered();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntroductionRequest getIntroductionRequest() {
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean wasAnswered() {
|
||||||
|
return answered;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAnswered(boolean answered) {
|
||||||
|
this.answered = answered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class is not thread-safe
|
||||||
|
static class Incoming extends IncomingConversationItem
|
||||||
|
implements ConversationIntroductionRequestItem {
|
||||||
|
|
||||||
|
private final IntroductionRequest ir;
|
||||||
|
private boolean answered;
|
||||||
|
|
||||||
|
public Incoming(IntroductionRequest ir) {
|
||||||
|
super(ir.getMessageId(), ir.getTimestamp(), ir.isRead());
|
||||||
|
|
||||||
|
this.ir = ir;
|
||||||
|
this.answered = ir.wasAnswered();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntroductionRequest getIntroductionRequest() {
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean wasAnswered() {
|
||||||
|
return answered;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAnswered(boolean answered) {
|
||||||
|
this.answered = answered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionResponseItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.introduction.IntroductionResponse;
|
||||||
|
|
||||||
|
class ConversationIntroductionResponseItemImpl {
|
||||||
|
|
||||||
|
static ConversationItem from(IntroductionResponse i) {
|
||||||
|
return i.isLocal() ? new Outgoing(i) : new Incoming(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Outgoing extends OutgoingConversationItem
|
||||||
|
implements ConversationIntroductionResponseItem {
|
||||||
|
|
||||||
|
private final IntroductionResponse ir;
|
||||||
|
|
||||||
|
public Outgoing(IntroductionResponse ir) {
|
||||||
|
super(ir.getMessageId(), ir.getTimestamp(), ir.isSent(), ir.isSeen());
|
||||||
|
|
||||||
|
this.ir = ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntroductionResponse getIntroductionResponse() {
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Incoming extends IncomingConversationItem
|
||||||
|
implements ConversationIntroductionResponseItem {
|
||||||
|
|
||||||
|
private final IntroductionResponse ir;
|
||||||
|
|
||||||
|
public Incoming(IntroductionResponse ir) {
|
||||||
|
super(ir.getMessageId(), ir.getTimestamp(), ir.isRead());
|
||||||
|
|
||||||
|
this.ir = ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntroductionResponse getIntroductionResponse() {
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
public abstract class ConversationItemImpl implements ConversationItem {
|
||||||
|
|
||||||
|
private final MessageId id;
|
||||||
|
private final long time;
|
||||||
|
|
||||||
|
public ConversationItemImpl(MessageId id, long time) {
|
||||||
|
this.id = id;
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.conversation.ConversationForumInvitationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionRequestItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationIntroductionResponseItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.OutgoingItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.Partial;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationMessageItem;
|
||||||
|
import org.briarproject.api.db.DatabaseExecutor;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.db.NoSuchMessageException;
|
||||||
|
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
||||||
|
import org.briarproject.api.event.Event;
|
||||||
|
import org.briarproject.api.event.EventBus;
|
||||||
|
import org.briarproject.api.event.EventListener;
|
||||||
|
import org.briarproject.api.event.ForumInvitationReceivedEvent;
|
||||||
|
import org.briarproject.api.event.IntroductionRequestReceivedEvent;
|
||||||
|
import org.briarproject.api.event.IntroductionResponseReceivedEvent;
|
||||||
|
import org.briarproject.api.event.PrivateMessageReceivedEvent;
|
||||||
|
import org.briarproject.api.forum.ForumInvitationMessage;
|
||||||
|
import org.briarproject.api.forum.ForumSharingManager;
|
||||||
|
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.PrivateMessage;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||||
|
import org.briarproject.api.sync.ClientId;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
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 ConversationManagerImpl implements ConversationManager,
|
||||||
|
EventListener {
|
||||||
|
|
||||||
|
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
|
||||||
|
"05313ec596871e5305181220488fc9c0"
|
||||||
|
+ "3d44985a48a6d0fb8767da3a6cae1cb4"));
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(ConversationManagerImpl.class.getName());
|
||||||
|
|
||||||
|
private final Executor dbExecutor;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final ForumSharingManager forumSharingManager;
|
||||||
|
private final IntroductionManager introductionManager;
|
||||||
|
private final MessagingManager messagingManager;
|
||||||
|
|
||||||
|
private Map<MessageId, byte[]> bodyCache =
|
||||||
|
new ConcurrentHashMap<MessageId, byte[]>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConversationManagerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
|
EventBus eventBus, ForumSharingManager forumSharingManager,
|
||||||
|
IntroductionManager introductionManager,
|
||||||
|
MessagingManager messagingManager) {
|
||||||
|
this.dbExecutor = dbExecutor;
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
this.forumSharingManager = forumSharingManager;
|
||||||
|
this.introductionManager = introductionManager;
|
||||||
|
this.messagingManager = messagingManager;
|
||||||
|
|
||||||
|
eventBus.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientId getClientId() {
|
||||||
|
return CLIENT_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem addLocalMessage(PrivateMessage m, byte[] body)
|
||||||
|
throws DbException {
|
||||||
|
messagingManager.addLocalMessage(m);
|
||||||
|
bodyCache.put(m.getMessage().getId(), body);
|
||||||
|
|
||||||
|
PrivateMessageHeader h = new PrivateMessageHeader(
|
||||||
|
m.getMessage().getId(),
|
||||||
|
m.getMessage().getTimestamp(), m.getContentType(),
|
||||||
|
true, false, false, false);
|
||||||
|
ConversationItem item = ConversationMessageItemImpl.from(h);
|
||||||
|
((Partial) item).setContent(body);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactId getContactId(GroupId g) throws DbException {
|
||||||
|
return messagingManager.getContactId(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupId getConversationId(ContactId c) throws DbException {
|
||||||
|
return messagingManager.getConversationId(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConversationItem> getMessages(ContactId c)
|
||||||
|
throws DbException {
|
||||||
|
Collection<PrivateMessageHeader> headers =
|
||||||
|
messagingManager.getMessageHeaders(c);
|
||||||
|
Collection<IntroductionMessage> introductions =
|
||||||
|
introductionManager.getIntroductionMessages(c);
|
||||||
|
Collection<ForumInvitationMessage> invitations =
|
||||||
|
forumSharingManager.getInvitationMessages(c);
|
||||||
|
List<ConversationItem> items = new ArrayList<ConversationItem>();
|
||||||
|
for (PrivateMessageHeader h : headers) {
|
||||||
|
ConversationItem item = ConversationMessageItemImpl.from(h);
|
||||||
|
byte[] body = bodyCache.get(h.getId());
|
||||||
|
if (body == null) loadMessageContent((Partial) item);
|
||||||
|
else ((Partial) item).setContent(body);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
for (IntroductionMessage m : introductions) {
|
||||||
|
ConversationItem item;
|
||||||
|
if (m instanceof IntroductionRequest) {
|
||||||
|
item = ConversationIntroductionRequestItemImpl.from(
|
||||||
|
(IntroductionRequest) m);
|
||||||
|
} else {
|
||||||
|
item = ConversationIntroductionResponseItemImpl.from(
|
||||||
|
(IntroductionResponse) m);
|
||||||
|
}
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
for (ForumInvitationMessage i : invitations) {
|
||||||
|
ConversationItem item = ConversationForumInvitationItemImpl.from(i);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTimestamp(ContactId c) throws DbException {
|
||||||
|
long timestamp = -1;
|
||||||
|
long t = messagingManager.getTimestamp(c);
|
||||||
|
if (t > timestamp) timestamp = t;
|
||||||
|
t = introductionManager.getTimestamp(c);
|
||||||
|
if (t > timestamp) timestamp = t;
|
||||||
|
t = forumSharingManager.getTimestamp(c);
|
||||||
|
if (t > timestamp) timestamp = t;
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getUnreadCount(ContactId c) throws DbException {
|
||||||
|
int unread = 0;
|
||||||
|
unread += messagingManager.getUnreadCount(c);
|
||||||
|
unread += introductionManager.getUnreadCount(c);
|
||||||
|
unread += forumSharingManager.getUnreadCount(c);
|
||||||
|
return unread;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMessageContent(final Partial m) {
|
||||||
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
MessageId id = m.getId();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
byte[] body = messagingManager.getMessageBody(id);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Loading message took " + duration + " ms");
|
||||||
|
bodyCache.put(id, body);
|
||||||
|
m.setContent(body);
|
||||||
|
} catch (NoSuchMessageException e) {
|
||||||
|
// The item will be removed when we get the event
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respondToItem(ContactId c, ConversationItem item,
|
||||||
|
boolean accept, long timestamp)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
if (item instanceof ConversationIntroductionRequestItem) {
|
||||||
|
SessionId sessionId = ((ConversationIntroductionRequestItem) item)
|
||||||
|
.getIntroductionRequest().getSessionId();
|
||||||
|
if (accept) {
|
||||||
|
introductionManager
|
||||||
|
.acceptIntroduction(c, sessionId,
|
||||||
|
timestamp);
|
||||||
|
} else {
|
||||||
|
introductionManager
|
||||||
|
.declineIntroduction(c, sessionId,
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadFlag(ContactId c, ConversationItem item, boolean read)
|
||||||
|
throws DbException {
|
||||||
|
MessageId id = item.getId();
|
||||||
|
boolean local = item instanceof OutgoingItem;
|
||||||
|
if (item instanceof ConversationMessageItem) {
|
||||||
|
messagingManager.setReadFlag(c, id, local, read);
|
||||||
|
} else if (item instanceof ConversationIntroductionRequestItem ||
|
||||||
|
item instanceof ConversationIntroductionResponseItem) {
|
||||||
|
introductionManager.setReadFlag(c, id, local, read);
|
||||||
|
} else if (item instanceof ConversationForumInvitationItem) {
|
||||||
|
forumSharingManager.setReadFlag(c, id, local, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof PrivateMessageReceivedEvent) {
|
||||||
|
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
||||||
|
PrivateMessageHeader h = p.getMessageHeader();
|
||||||
|
ConversationItem m = ConversationMessageItemImpl.from(h);
|
||||||
|
loadMessageContent((Partial) m);
|
||||||
|
try {
|
||||||
|
ContactId c = getContactId(p.getGroupId());
|
||||||
|
eventBus.broadcast(new ConversationItemReceivedEvent(m, c));
|
||||||
|
} catch (DbException dbe) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, dbe.toString(), dbe);
|
||||||
|
}
|
||||||
|
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
||||||
|
IntroductionRequestReceivedEvent event =
|
||||||
|
(IntroductionRequestReceivedEvent) e;
|
||||||
|
IntroductionRequest ir = event.getIntroductionRequest();
|
||||||
|
ConversationItem item =
|
||||||
|
ConversationIntroductionRequestItemImpl.from(ir);
|
||||||
|
eventBus.broadcast(
|
||||||
|
new ConversationItemReceivedEvent(item,
|
||||||
|
event.getContactId()));
|
||||||
|
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
||||||
|
IntroductionResponseReceivedEvent event =
|
||||||
|
(IntroductionResponseReceivedEvent) e;
|
||||||
|
IntroductionResponse ir = event.getIntroductionResponse();
|
||||||
|
ConversationItem item =
|
||||||
|
ConversationIntroductionResponseItemImpl.from(ir);
|
||||||
|
eventBus.broadcast(new ConversationItemReceivedEvent(item,
|
||||||
|
event.getContactId()));
|
||||||
|
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||||
|
ForumInvitationReceivedEvent event =
|
||||||
|
(ForumInvitationReceivedEvent) e;
|
||||||
|
try {
|
||||||
|
ForumInvitationMessage fim = forumSharingManager
|
||||||
|
.getInvitationMessage(event.getContactId(),
|
||||||
|
event.getMessageId());
|
||||||
|
ConversationItem item =
|
||||||
|
ConversationForumInvitationItemImpl.from(fim);
|
||||||
|
eventBus.broadcast(new ConversationItemReceivedEvent(item,
|
||||||
|
event.getContactId()));
|
||||||
|
} catch (DbException dbe) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, dbe.toString(), dbe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationMessageItem;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||||
|
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
class ConversationMessageItemImpl {
|
||||||
|
|
||||||
|
static ConversationItem from(PrivateMessageHeader h) {
|
||||||
|
return h.isLocal() ? new Outgoing(h) : new Incoming(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Outgoing extends OutgoingConversationItem
|
||||||
|
implements ConversationMessageItem {
|
||||||
|
|
||||||
|
private final PrivateMessageHeader header;
|
||||||
|
private byte[] body;
|
||||||
|
private ContentListener listener;
|
||||||
|
private final ReentrantReadWriteLock bodyLock =
|
||||||
|
new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantReadWriteLock listenerLock =
|
||||||
|
new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
public Outgoing(PrivateMessageHeader header) {
|
||||||
|
super(header.getId(), header.getTimestamp(), header.isSent(),
|
||||||
|
header.isSeen());
|
||||||
|
|
||||||
|
this.header = header;
|
||||||
|
body = null;
|
||||||
|
listener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrivateMessageHeader getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBody() {
|
||||||
|
bodyLock.readLock().lock();
|
||||||
|
byte[] ret = body;
|
||||||
|
bodyLock.readLock().unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContent(byte[] content) {
|
||||||
|
bodyLock.writeLock().lock();
|
||||||
|
this.body = content;
|
||||||
|
bodyLock.writeLock().unlock();
|
||||||
|
listenerLock.readLock().lock();
|
||||||
|
if (listener != null) {
|
||||||
|
listener.contentReady();
|
||||||
|
}
|
||||||
|
listenerLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentListener(
|
||||||
|
ContentListener listener) {
|
||||||
|
listenerLock.writeLock().lock();
|
||||||
|
this.listener = listener;
|
||||||
|
listenerLock.writeLock().unlock();
|
||||||
|
bodyLock.readLock().lock();
|
||||||
|
if (body != null) {
|
||||||
|
listener.contentReady();
|
||||||
|
}
|
||||||
|
bodyLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Incoming extends IncomingConversationItem
|
||||||
|
implements ConversationMessageItem {
|
||||||
|
|
||||||
|
private final PrivateMessageHeader header;
|
||||||
|
private byte[] body;
|
||||||
|
private ContentListener listener;
|
||||||
|
private final ReentrantReadWriteLock bodyLock =
|
||||||
|
new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantReadWriteLock listenerLock =
|
||||||
|
new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
public Incoming(PrivateMessageHeader header) {
|
||||||
|
super(header.getId(), header.getTimestamp(), header.isRead());
|
||||||
|
|
||||||
|
this.header = header;
|
||||||
|
body = null;
|
||||||
|
listener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrivateMessageHeader getHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBody() {
|
||||||
|
bodyLock.readLock().lock();
|
||||||
|
byte[] ret = body;
|
||||||
|
bodyLock.readLock().unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContent(byte[] content) {
|
||||||
|
bodyLock.writeLock().lock();
|
||||||
|
this.body = content;
|
||||||
|
bodyLock.writeLock().unlock();
|
||||||
|
listenerLock.readLock().lock();
|
||||||
|
if (listener != null) {
|
||||||
|
listener.contentReady();
|
||||||
|
}
|
||||||
|
listenerLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentListener(
|
||||||
|
ContentListener listener) {
|
||||||
|
listenerLock.writeLock().lock();
|
||||||
|
this.listener = listener;
|
||||||
|
listenerLock.writeLock().unlock();
|
||||||
|
bodyLock.readLock().lock();
|
||||||
|
if (body != null) {
|
||||||
|
listener.contentReady();
|
||||||
|
}
|
||||||
|
bodyLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class ConversationModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
ConversationManager conversationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ConversationManager getConversationManager(
|
||||||
|
ConversationManagerImpl conversationManager) {
|
||||||
|
return conversationManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
// This class is not thread-safe
|
||||||
|
class IncomingConversationItem extends ConversationItemImpl
|
||||||
|
implements IncomingItem {
|
||||||
|
|
||||||
|
private boolean read;
|
||||||
|
|
||||||
|
public IncomingConversationItem(MessageId id, long time, boolean read) {
|
||||||
|
super(id, time);
|
||||||
|
|
||||||
|
this.read = read;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRead() {
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRead(boolean read) {
|
||||||
|
this.read = read;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,24 @@
|
|||||||
package org.briarproject.android.contact;
|
package org.briarproject.conversation;
|
||||||
|
|
||||||
|
import org.briarproject.api.conversation.ConversationItem.OutgoingItem;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
public class ConversationNoticeOutItem extends ConversationNoticeItem
|
class OutgoingConversationItem extends ConversationItemImpl
|
||||||
implements ConversationItem.OutgoingItem {
|
implements OutgoingItem {
|
||||||
|
|
||||||
private boolean sent, seen;
|
private boolean sent, seen;
|
||||||
|
|
||||||
public ConversationNoticeOutItem(MessageId id, String text, long time,
|
public OutgoingConversationItem(MessageId id, long time, boolean sent,
|
||||||
boolean sent, boolean seen) {
|
boolean seen) {
|
||||||
super(id, text, time);
|
super(id, time);
|
||||||
|
|
||||||
this.sent = sent;
|
this.sent = sent;
|
||||||
this.seen = seen;
|
this.seen = seen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getType() {
|
public boolean isSent() {
|
||||||
return NOTICE_OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSent() {
|
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ABORT;
|
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ABORT;
|
||||||
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ACCEPT;
|
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_ACCEPT;
|
||||||
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_DECLINE;
|
import static org.briarproject.api.introduction.IntroduceeAction.LOCAL_DECLINE;
|
||||||
@@ -112,7 +113,7 @@ public class IntroduceeEngine
|
|||||||
msg.put(E_PUBLIC_KEY, localState.getRaw(OUR_PUBLIC_KEY));
|
msg.put(E_PUBLIC_KEY, localState.getRaw(OUR_PUBLIC_KEY));
|
||||||
msg.put(TRANSPORT, localAction.getDictionary(TRANSPORT));
|
msg.put(TRANSPORT, localAction.getDictionary(TRANSPORT));
|
||||||
}
|
}
|
||||||
msg.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME));
|
msg.put(TIMESTAMP, localAction.getLong(MESSAGE_TIME));
|
||||||
messages.add(msg);
|
messages.add(msg);
|
||||||
logAction(currentState, localState, msg);
|
logAction(currentState, localState, msg);
|
||||||
|
|
||||||
@@ -330,7 +331,7 @@ public class IntroduceeEngine
|
|||||||
|
|
||||||
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
|
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
|
||||||
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
|
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
|
||||||
long time = msg.getLong(MESSAGE_TIME);
|
long time = msg.getLong(TIMESTAMP);
|
||||||
String name = msg.getString(NAME);
|
String name = msg.getString(NAME);
|
||||||
String message = msg.getOptionalString(MSG);
|
String message = msg.getOptionalString(MSG);
|
||||||
boolean exists = localState.getBoolean(EXISTS);
|
boolean exists = localState.getBoolean(EXISTS);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.introduction.IntroducerAction.LOCAL_ABORT;
|
import static org.briarproject.api.introduction.IntroducerAction.LOCAL_ABORT;
|
||||||
import static org.briarproject.api.introduction.IntroducerAction.LOCAL_REQUEST;
|
import static org.briarproject.api.introduction.IntroducerAction.LOCAL_REQUEST;
|
||||||
import static org.briarproject.api.introduction.IntroducerAction.REMOTE_ACCEPT_1;
|
import static org.briarproject.api.introduction.IntroducerAction.REMOTE_ACCEPT_1;
|
||||||
@@ -106,7 +107,7 @@ public class IntroducerEngine
|
|||||||
if (localAction.containsKey(MSG)) {
|
if (localAction.containsKey(MSG)) {
|
||||||
msg1.put(MSG, localAction.getString(MSG));
|
msg1.put(MSG, localAction.getString(MSG));
|
||||||
}
|
}
|
||||||
msg1.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME));
|
msg1.put(TIMESTAMP, localAction.getLong(MESSAGE_TIME));
|
||||||
messages.add(msg1);
|
messages.add(msg1);
|
||||||
logLocalAction(currentState, localState, msg1);
|
logLocalAction(currentState, localState, msg1);
|
||||||
BdfDictionary msg2 = new BdfDictionary();
|
BdfDictionary msg2 = new BdfDictionary();
|
||||||
@@ -118,7 +119,7 @@ public class IntroducerEngine
|
|||||||
if (localAction.containsKey(MSG)) {
|
if (localAction.containsKey(MSG)) {
|
||||||
msg2.put(MSG, localAction.getString(MSG));
|
msg2.put(MSG, localAction.getString(MSG));
|
||||||
}
|
}
|
||||||
msg2.put(MESSAGE_TIME, localAction.getLong(MESSAGE_TIME));
|
msg2.put(TIMESTAMP, localAction.getLong(MESSAGE_TIME));
|
||||||
messages.add(msg2);
|
messages.add(msg2);
|
||||||
logLocalAction(currentState, localState, msg2);
|
logLocalAction(currentState, localState, msg2);
|
||||||
|
|
||||||
@@ -298,7 +299,7 @@ public class IntroducerEngine
|
|||||||
|
|
||||||
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
|
SessionId sessionId = new SessionId(localState.getRaw(SESSION_ID));
|
||||||
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
|
MessageId messageId = new MessageId(msg.getRaw(MESSAGE_ID));
|
||||||
long time = msg.getLong(MESSAGE_TIME);
|
long time = msg.getLong(TIMESTAMP);
|
||||||
String name = getOtherContact(localState, msg);
|
String name = getOtherContact(localState, msg);
|
||||||
boolean accept = msg.getBoolean(ACCEPT);
|
boolean accept = msg.getBoolean(ACCEPT);
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ import org.briarproject.api.introduction.IntroductionResponse;
|
|||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.Group;
|
import org.briarproject.api.sync.Group;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.api.sync.Message;
|
import org.briarproject.api.sync.Message;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
import org.briarproject.api.sync.MessageStatus;
|
import org.briarproject.api.sync.MessageStatus;
|
||||||
import org.briarproject.clients.BdfIncomingMessageHook;
|
import org.briarproject.clients.ReadableMessageManagerImpl;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -42,6 +43,8 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.introduction.IntroduceeProtocolState.FINISHED;
|
import static org.briarproject.api.introduction.IntroduceeProtocolState.FINISHED;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ANSWERED;
|
import static org.briarproject.api.introduction.IntroductionConstants.ANSWERED;
|
||||||
@@ -56,11 +59,9 @@ import static org.briarproject.api.introduction.IntroductionConstants.EXISTS;
|
|||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
|
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.READ;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
|
import static org.briarproject.api.introduction.IntroductionConstants.REMOTE_AUTHOR_IS_US;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1;
|
import static org.briarproject.api.introduction.IntroductionConstants.RESPONSE_1;
|
||||||
@@ -76,7 +77,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
|
|||||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||||
|
|
||||||
class IntroductionManagerImpl extends BdfIncomingMessageHook
|
class IntroductionManagerImpl extends ReadableMessageManagerImpl
|
||||||
implements IntroductionManager, Client, AddContactHook,
|
implements IntroductionManager, Client, AddContactHook,
|
||||||
RemoveContactHook {
|
RemoveContactHook {
|
||||||
|
|
||||||
@@ -87,7 +88,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(IntroductionManagerImpl.class.getName());
|
Logger.getLogger(IntroductionManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
|
||||||
private final IntroducerManager introducerManager;
|
private final IntroducerManager introducerManager;
|
||||||
private final IntroduceeManager introduceeManager;
|
private final IntroduceeManager introduceeManager;
|
||||||
private final IntroductionGroupFactory introductionGroupFactory;
|
private final IntroductionGroupFactory introductionGroupFactory;
|
||||||
@@ -98,8 +98,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
IntroduceeManager introduceeManager,
|
IntroduceeManager introduceeManager,
|
||||||
IntroductionGroupFactory introductionGroupFactory) {
|
IntroductionGroupFactory introductionGroupFactory) {
|
||||||
|
|
||||||
super(clientHelper, metadataParser);
|
super(clientHelper, db, metadataParser);
|
||||||
this.db = db;
|
|
||||||
this.introducerManager = introducerManager;
|
this.introducerManager = introducerManager;
|
||||||
this.introduceeManager = introduceeManager;
|
this.introduceeManager = introduceeManager;
|
||||||
this.introductionGroupFactory = introductionGroupFactory;
|
this.introductionGroupFactory = introductionGroupFactory;
|
||||||
@@ -166,8 +165,10 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
.getMessageMetadataAsDictionary(txn, gId, query);
|
.getMessageMetadataAsDictionary(txn, gId, query);
|
||||||
for (Map.Entry<MessageId, BdfDictionary> entry : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> entry : map.entrySet()) {
|
||||||
BdfDictionary d = entry.getValue();
|
BdfDictionary d = entry.getValue();
|
||||||
ContactId c1 = new ContactId(d.getLong(CONTACT_ID_1).intValue());
|
ContactId c1 =
|
||||||
ContactId c2 = new ContactId(d.getLong(CONTACT_ID_2).intValue());
|
new ContactId(d.getLong(CONTACT_ID_1).intValue());
|
||||||
|
ContactId c2 =
|
||||||
|
new ContactId(d.getLong(CONTACT_ID_2).intValue());
|
||||||
|
|
||||||
if (c1.equals(c.getId()) || c2.equals(c.getId())) {
|
if (c1.equals(c.getId()) || c2.equals(c.getId())) {
|
||||||
IntroducerProtocolState state = IntroducerProtocolState
|
IntroducerProtocolState state = IntroducerProtocolState
|
||||||
@@ -198,7 +199,13 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
|
|
||||||
// remove the group (all messages will be removed with it)
|
// remove the group (all messages will be removed with it)
|
||||||
// this contact won't get our abort message, but the other will
|
// this contact won't get our abort message, but the other will
|
||||||
db.removeGroup(txn, introductionGroupFactory.createIntroductionGroup(c));
|
db.removeGroup(txn,
|
||||||
|
introductionGroupFactory.createIntroductionGroup(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Group getContactGroup(Contact c) {
|
||||||
|
return introductionGroupFactory.createIntroductionGroup(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -207,8 +214,9 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
* in the introduction protocol and which engine we need to start.
|
* in the introduction protocol and which engine we need to start.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
protected void incomingReadableMessage(Transaction txn, Message m,
|
||||||
BdfDictionary message) throws DbException {
|
BdfList body, BdfDictionary message)
|
||||||
|
throws DbException, FormatException, InvalidMessageException {
|
||||||
|
|
||||||
// Get message data and type
|
// Get message data and type
|
||||||
GroupId groupId = m.getGroupId();
|
GroupId groupId = m.getGroupId();
|
||||||
@@ -218,7 +226,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
if (type == TYPE_REQUEST) {
|
if (type == TYPE_REQUEST) {
|
||||||
boolean stateExists = true;
|
boolean stateExists = true;
|
||||||
try {
|
try {
|
||||||
getSessionState(txn, groupId, message.getRaw(SESSION_ID), false);
|
getSessionState(txn, groupId, message.getRaw(SESSION_ID),
|
||||||
|
false);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
stateExists = false;
|
stateExists = false;
|
||||||
}
|
}
|
||||||
@@ -233,7 +242,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
deleteMessage(txn, m.getId());
|
deleteMessage(txn, m.getId());
|
||||||
return;
|
throw new InvalidMessageException();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
introduceeManager.incomingMessage(txn, state, message);
|
introduceeManager.incomingMessage(txn, state, message);
|
||||||
@@ -246,7 +255,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// our role can be anything
|
// our role can be anything
|
||||||
else if (type == TYPE_RESPONSE || type == TYPE_ACK || type == TYPE_ABORT) {
|
else if (type == TYPE_RESPONSE || type == TYPE_ACK ||
|
||||||
|
type == TYPE_ABORT) {
|
||||||
BdfDictionary state;
|
BdfDictionary state;
|
||||||
try {
|
try {
|
||||||
state = getSessionState(txn, groupId,
|
state = getSessionState(txn, groupId,
|
||||||
@@ -254,7 +264,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
LOG.warning("Could not find state for message, deleting...");
|
LOG.warning("Could not find state for message, deleting...");
|
||||||
deleteMessage(txn, m.getId());
|
deleteMessage(txn, m.getId());
|
||||||
return;
|
throw new InvalidMessageException();
|
||||||
}
|
}
|
||||||
|
|
||||||
long role = state.getLong(ROLE, -1L);
|
long role = state.getLong(ROLE, -1L);
|
||||||
@@ -264,26 +274,31 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
} else if (role == ROLE_INTRODUCEE) {
|
} else if (role == ROLE_INTRODUCEE) {
|
||||||
introduceeManager.incomingMessage(txn, state, message);
|
introduceeManager.incomingMessage(txn, state, message);
|
||||||
} else {
|
} else {
|
||||||
if(LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Unknown role '" + role +
|
LOG.warning("Unknown role '" + role +
|
||||||
"'. Deleting message...");
|
"'. Deleting message...");
|
||||||
deleteMessage(txn, m.getId());
|
|
||||||
}
|
}
|
||||||
|
deleteMessage(txn, m.getId());
|
||||||
|
throw new InvalidMessageException();
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state);
|
if (role == ROLE_INTRODUCER)
|
||||||
|
introducerManager.abort(txn, state);
|
||||||
else introduceeManager.abort(txn, state);
|
else introduceeManager.abort(txn, state);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
if (role == ROLE_INTRODUCER) introducerManager.abort(txn, state);
|
if (role == ROLE_INTRODUCER)
|
||||||
|
introducerManager.abort(txn, state);
|
||||||
else introduceeManager.abort(txn, state);
|
else introduceeManager.abort(txn, state);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// the message has been validated, so this should not happen
|
// the message has been validated, so this should not happen
|
||||||
if(LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Unknown message type '" + type + "', deleting...");
|
LOG.warning("Unknown message type '" + type + "', deleting...");
|
||||||
}
|
}
|
||||||
|
deleteMessage(txn, m.getId());
|
||||||
|
throw new InvalidMessageException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +310,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp);
|
introducerManager.makeIntroduction(txn, c1, c2, msg, timestamp);
|
||||||
|
updateContactMetadata(txn, c1.getId(), timestamp, true, true, true);
|
||||||
|
updateContactMetadata(txn, c2.getId(), timestamp, true, true, true);
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
@@ -314,6 +331,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
getSessionState(txn, g.getId(), sessionId.getBytes());
|
getSessionState(txn, g.getId(), sessionId.getBytes());
|
||||||
|
|
||||||
introduceeManager.acceptIntroduction(txn, state, timestamp);
|
introduceeManager.acceptIntroduction(txn, state, timestamp);
|
||||||
|
updateContactMetadata(txn, contactId, timestamp, true, true, true);
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
@@ -333,6 +351,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
getSessionState(txn, g.getId(), sessionId.getBytes());
|
getSessionState(txn, g.getId(), sessionId.getBytes());
|
||||||
|
|
||||||
introduceeManager.declineIntroduction(txn, state, timestamp);
|
introduceeManager.declineIntroduction(txn, state, timestamp);
|
||||||
|
updateContactMetadata(txn, contactId, timestamp, true, true, true);
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
@@ -374,14 +393,15 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
|
|
||||||
int role = state.getLong(ROLE).intValue();
|
int role = state.getLong(ROLE).intValue();
|
||||||
boolean local;
|
boolean local;
|
||||||
long time = msg.getLong(MESSAGE_TIME);
|
long time = msg.getLong(TIMESTAMP);
|
||||||
boolean accepted = msg.getBoolean(ACCEPT, false);
|
boolean accepted = msg.getBoolean(ACCEPT, false);
|
||||||
boolean read = msg.getBoolean(READ, false);
|
boolean read = msg.getBoolean(READ, false);
|
||||||
AuthorId authorId;
|
AuthorId authorId;
|
||||||
String name;
|
String name;
|
||||||
if (type == TYPE_RESPONSE) {
|
if (type == TYPE_RESPONSE) {
|
||||||
if (role == ROLE_INTRODUCER) {
|
if (role == ROLE_INTRODUCER) {
|
||||||
if (!concernsThisContact(contactId, messageId, state)) {
|
if (!concernsThisContact(contactId, messageId,
|
||||||
|
state)) {
|
||||||
// this response is not from contactId
|
// this response is not from contactId
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -445,7 +465,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
list.add(ir);
|
list.add(ir);
|
||||||
}
|
}
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txn.setComplete();
|
txn.setComplete();
|
||||||
@@ -464,7 +485,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
return state.getString(CONTACT_2);
|
return state.getString(CONTACT_2);
|
||||||
if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue())
|
if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue())
|
||||||
return state.getString(CONTACT_1);
|
return state.getString(CONTACT_1);
|
||||||
throw new RuntimeException("Contact not part of this introduction session");
|
throw new RuntimeException(
|
||||||
|
"Contact not part of this introduction session");
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthorId getAuthorIdForIntroducer(ContactId contactId,
|
private AuthorId getAuthorIdForIntroducer(ContactId contactId,
|
||||||
@@ -474,10 +496,12 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
return new AuthorId(state.getRaw(AUTHOR_ID_2));
|
return new AuthorId(state.getRaw(AUTHOR_ID_2));
|
||||||
if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue())
|
if (contactId.getInt() == state.getLong(CONTACT_ID_2).intValue())
|
||||||
return new AuthorId(state.getRaw(AUTHOR_ID_1));
|
return new AuthorId(state.getRaw(AUTHOR_ID_1));
|
||||||
throw new RuntimeException("Contact not part of this introduction session");
|
throw new RuntimeException(
|
||||||
|
"Contact not part of this introduction session");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean concernsThisContact(ContactId contactId, MessageId messageId,
|
private boolean concernsThisContact(ContactId contactId,
|
||||||
|
MessageId messageId,
|
||||||
BdfDictionary state) throws FormatException {
|
BdfDictionary state) throws FormatException {
|
||||||
|
|
||||||
if (contactId.getInt() == state.getLong(CONTACT_ID_1).intValue()) {
|
if (contactId.getInt() == state.getLong(CONTACT_ID_1).intValue()) {
|
||||||
@@ -509,7 +533,8 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook
|
|||||||
// to find state for introducee
|
// to find state for introducee
|
||||||
Map<MessageId, BdfDictionary> map = clientHelper
|
Map<MessageId, BdfDictionary> map = clientHelper
|
||||||
.getMessageMetadataAsDictionary(txn,
|
.getMessageMetadataAsDictionary(txn,
|
||||||
introductionGroupFactory.createLocalGroup().getId());
|
introductionGroupFactory.createLocalGroup()
|
||||||
|
.getId());
|
||||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||||
if (Arrays.equals(m.getValue().getRaw(SESSION_ID), sessionId)) {
|
if (Arrays.equals(m.getValue().getRaw(SESSION_ID), sessionId)) {
|
||||||
BdfDictionary state = m.getValue();
|
BdfDictionary state = m.getValue();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.briarproject.introduction;
|
package org.briarproject.introduction;
|
||||||
|
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.clients.BdfMessageContext;
|
||||||
import org.briarproject.api.clients.ClientHelper;
|
import org.briarproject.api.clients.ClientHelper;
|
||||||
import org.briarproject.api.clients.SessionId;
|
import org.briarproject.api.clients.SessionId;
|
||||||
import org.briarproject.api.clients.BdfMessageContext;
|
|
||||||
import org.briarproject.api.data.BdfDictionary;
|
import org.briarproject.api.data.BdfDictionary;
|
||||||
import org.briarproject.api.data.BdfList;
|
import org.briarproject.api.data.BdfList;
|
||||||
import org.briarproject.api.data.MetadataEncoder;
|
import org.briarproject.api.data.MetadataEncoder;
|
||||||
@@ -13,13 +13,15 @@ import org.briarproject.api.system.Clock;
|
|||||||
import org.briarproject.clients.BdfMessageValidator;
|
import org.briarproject.clients.BdfMessageValidator;
|
||||||
|
|
||||||
import static org.briarproject.api.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
import static org.briarproject.api.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
||||||
@@ -67,7 +69,9 @@ class IntroductionValidator extends BdfMessageValidator {
|
|||||||
d.put(SESSION_ID, id);
|
d.put(SESSION_ID, id);
|
||||||
d.put(GROUP_ID, m.getGroupId());
|
d.put(GROUP_ID, m.getGroupId());
|
||||||
d.put(MESSAGE_ID, m.getId());
|
d.put(MESSAGE_ID, m.getId());
|
||||||
d.put(MESSAGE_TIME, m.getTimestamp());
|
d.put(TIMESTAMP, m.getTimestamp());
|
||||||
|
d.put(LOCAL, false);
|
||||||
|
d.put(READ, false);
|
||||||
return new BdfMessageContext(d);
|
return new BdfMessageContext(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ import org.briarproject.api.system.Clock;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
||||||
@@ -61,7 +61,7 @@ public class MessageSender {
|
|||||||
Group group = db.getGroup(txn, groupId);
|
Group group = db.getGroup(txn, groupId);
|
||||||
long timestamp = clock.currentTimeMillis();
|
long timestamp = clock.currentTimeMillis();
|
||||||
|
|
||||||
message.put(MESSAGE_TIME, timestamp);
|
message.put(TIMESTAMP, timestamp);
|
||||||
Metadata metadata = metadataEncoder.encode(message);
|
Metadata metadata = metadataEncoder.encode(message);
|
||||||
|
|
||||||
messageQueueManager
|
messageQueueManager
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ import org.briarproject.api.messaging.PrivateMessageHeader;
|
|||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.Group;
|
import org.briarproject.api.sync.Group;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.api.sync.Message;
|
import org.briarproject.api.sync.Message;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
import org.briarproject.api.sync.MessageStatus;
|
import org.briarproject.api.sync.MessageStatus;
|
||||||
import org.briarproject.clients.BdfIncomingMessageHook;
|
import org.briarproject.clients.ReadableMessageManagerImpl;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -33,23 +34,25 @@ import java.util.Map;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
class MessagingManagerImpl extends BdfIncomingMessageHook
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
|
|
||||||
|
class MessagingManagerImpl extends ReadableMessageManagerImpl
|
||||||
implements MessagingManager, Client, AddContactHook, RemoveContactHook {
|
implements MessagingManager, Client, AddContactHook, RemoveContactHook {
|
||||||
|
|
||||||
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
|
static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
|
||||||
"6bcdc006c0910b0f44e40644c3b31f1a"
|
"6bcdc006c0910b0f44e40644c3b31f1a"
|
||||||
+ "8bf9a6d6021d40d219c86b731b903070"));
|
+ "8bf9a6d6021d40d219c86b731b903070"));
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
|
||||||
private final PrivateGroupFactory privateGroupFactory;
|
private final PrivateGroupFactory privateGroupFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||||
MetadataParser metadataParser,
|
MetadataParser metadataParser,
|
||||||
PrivateGroupFactory privateGroupFactory) {
|
PrivateGroupFactory privateGroupFactory) {
|
||||||
super(clientHelper, metadataParser);
|
super(clientHelper, db, metadataParser);
|
||||||
|
|
||||||
this.db = db;
|
|
||||||
this.privateGroupFactory = privateGroupFactory;
|
this.privateGroupFactory = privateGroupFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +81,8 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Group getContactGroup(Contact c) {
|
@Override
|
||||||
|
protected Group getContactGroup(Contact c) {
|
||||||
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
|
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,14 +97,16 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
protected void incomingReadableMessage(Transaction txn, Message m,
|
||||||
BdfDictionary meta) throws DbException, FormatException {
|
BdfList body, BdfDictionary meta)
|
||||||
|
throws DbException, FormatException, InvalidMessageException {
|
||||||
|
|
||||||
|
// Broadcast event
|
||||||
GroupId groupId = m.getGroupId();
|
GroupId groupId = m.getGroupId();
|
||||||
long timestamp = meta.getLong("timestamp");
|
long timestamp = meta.getLong(TIMESTAMP);
|
||||||
String contentType = meta.getString("contentType");
|
String contentType = meta.getString("contentType");
|
||||||
boolean local = meta.getBoolean("local");
|
boolean local = meta.getBoolean(LOCAL);
|
||||||
boolean read = meta.getBoolean("read");
|
boolean read = meta.getBoolean(READ);
|
||||||
PrivateMessageHeader header = new PrivateMessageHeader(
|
PrivateMessageHeader header = new PrivateMessageHeader(
|
||||||
m.getId(), timestamp, contentType, local, read, false, false);
|
m.getId(), timestamp, contentType, local, read, false, false);
|
||||||
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
|
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
|
||||||
@@ -110,16 +116,23 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addLocalMessage(PrivateMessage m) throws DbException {
|
public void addLocalMessage(PrivateMessage m) throws DbException {
|
||||||
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put("timestamp", m.getMessage().getTimestamp());
|
meta.put(TIMESTAMP, m.getMessage().getTimestamp());
|
||||||
if (m.getParent() != null) meta.put("parent", m.getParent());
|
if (m.getParent() != null) meta.put("parent", m.getParent());
|
||||||
meta.put("contentType", m.getContentType());
|
meta.put("contentType", m.getContentType());
|
||||||
meta.put("local", true);
|
meta.put(LOCAL, true);
|
||||||
meta.put("read", true);
|
meta.put(READ, true);
|
||||||
clientHelper.addLocalMessage(m.getMessage(), CLIENT_ID, meta, true);
|
clientHelper.addLocalMessage(txn, m.getMessage(), CLIENT_ID, meta,
|
||||||
|
true);
|
||||||
|
updateGroupMetadata(txn, m.getMessage().getGroupId(),
|
||||||
|
m.getMessage().getTimestamp(), true, true, true);
|
||||||
|
txn.setComplete();
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,10 +182,10 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
|||||||
BdfDictionary meta = metadata.get(id);
|
BdfDictionary meta = metadata.get(id);
|
||||||
if (meta == null) continue;
|
if (meta == null) continue;
|
||||||
try {
|
try {
|
||||||
long timestamp = meta.getLong("timestamp");
|
long timestamp = meta.getLong(TIMESTAMP);
|
||||||
String contentType = meta.getString("contentType");
|
String contentType = meta.getString("contentType");
|
||||||
boolean local = meta.getBoolean("local");
|
boolean local = meta.getBoolean(LOCAL);
|
||||||
boolean read = meta.getBoolean("read");
|
boolean read = meta.getBoolean(READ);
|
||||||
headers.add(new PrivateMessageHeader(id, timestamp, contentType,
|
headers.add(new PrivateMessageHeader(id, timestamp, contentType,
|
||||||
local, read, s.isSent(), s.isSeen()));
|
local, read, s.isSent(), s.isSeen()));
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -192,15 +205,4 @@ class MessagingManagerImpl extends BdfIncomingMessageHook
|
|||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadFlag(MessageId m, boolean read) throws DbException {
|
|
||||||
try {
|
|
||||||
BdfDictionary meta = new BdfDictionary();
|
|
||||||
meta.put("read", read);
|
|
||||||
clientHelper.mergeMessageMetadata(m, meta);
|
|
||||||
} catch (FormatException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import org.briarproject.api.sync.Message;
|
|||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.clients.BdfMessageValidator;
|
import org.briarproject.clients.BdfMessageValidator;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
|
||||||
|
|
||||||
@@ -38,11 +41,11 @@ class PrivateMessageValidator extends BdfMessageValidator {
|
|||||||
checkLength(privateMessageBody, 0, MAX_PRIVATE_MESSAGE_BODY_LENGTH);
|
checkLength(privateMessageBody, 0, MAX_PRIVATE_MESSAGE_BODY_LENGTH);
|
||||||
// Return the metadata
|
// Return the metadata
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put("timestamp", m.getTimestamp());
|
meta.put(TIMESTAMP, m.getTimestamp());
|
||||||
if (parentId != null) meta.put("parent", parentId);
|
if (parentId != null) meta.put("parent", parentId);
|
||||||
meta.put("contentType", contentType);
|
meta.put("contentType", contentType);
|
||||||
meta.put("local", false);
|
meta.put(LOCAL, false);
|
||||||
meta.put("read", false);
|
meta.put(READ, false);
|
||||||
return new BdfMessageContext(meta);
|
return new BdfMessageContext(meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ class BlogSharingManagerImpl extends
|
|||||||
|
|
||||||
private final SFactory sFactory;
|
private final SFactory sFactory;
|
||||||
private final IFactory iFactory;
|
private final IFactory iFactory;
|
||||||
|
private final IMFactory imFactory;
|
||||||
private final ISFactory isFactory;
|
private final ISFactory isFactory;
|
||||||
private final SSFactory ssFactory;
|
private final SSFactory ssFactory;
|
||||||
private final IRFactory irFactory;
|
private final IRFactory irFactory;
|
||||||
@@ -69,6 +70,7 @@ class BlogSharingManagerImpl extends
|
|||||||
|
|
||||||
sFactory = new SFactory(authorFactory, blogFactory, blogManager);
|
sFactory = new SFactory(authorFactory, blogFactory, blogManager);
|
||||||
iFactory = new IFactory();
|
iFactory = new IFactory();
|
||||||
|
imFactory = new IMFactory();
|
||||||
isFactory = new ISFactory();
|
isFactory = new ISFactory();
|
||||||
ssFactory = new SSFactory();
|
ssFactory = new SSFactory();
|
||||||
irFactory = new IRFactory(sFactory);
|
irFactory = new IRFactory(sFactory);
|
||||||
@@ -80,16 +82,6 @@ class BlogSharingManagerImpl extends
|
|||||||
return CLIENT_ID;
|
return CLIENT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected BlogInvitationMessage createInvitationMessage(MessageId id,
|
|
||||||
BlogInvitation msg, ContactId contactId, boolean available,
|
|
||||||
long time, boolean local, boolean sent, boolean seen,
|
|
||||||
boolean read) {
|
|
||||||
return new BlogInvitationMessage(id, msg.getSessionId(), contactId,
|
|
||||||
msg.getBlogTitle(), msg.getMessage(), available, time, local,
|
|
||||||
sent, seen, read);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() {
|
protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() {
|
||||||
return sFactory;
|
return sFactory;
|
||||||
@@ -100,6 +92,11 @@ class BlogSharingManagerImpl extends
|
|||||||
return iFactory;
|
return iFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InvitationMessageFactory<BlogInvitation, BlogInvitationMessage> getIMFactory() {
|
||||||
|
return imFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InviteeSessionStateFactory<Blog, BlogInviteeSessionState> getISFactory() {
|
protected InviteeSessionStateFactory<Blog, BlogInviteeSessionState> getISFactory() {
|
||||||
return isFactory;
|
return isFactory;
|
||||||
@@ -207,6 +204,20 @@ class BlogSharingManagerImpl extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class IMFactory implements
|
||||||
|
InvitationMessageFactory<BlogInvitation, BlogInvitationMessage> {
|
||||||
|
@Override
|
||||||
|
public BlogInvitationMessage build(MessageId id,
|
||||||
|
BlogInvitation msg, ContactId contactId,
|
||||||
|
boolean available, long time, boolean local, boolean sent,
|
||||||
|
boolean seen, boolean read) {
|
||||||
|
return new BlogInvitationMessage(id, msg.getSessionId(), contactId,
|
||||||
|
msg.getBlogTitle(), msg.getMessage(), available, time,
|
||||||
|
local,
|
||||||
|
sent, seen, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class ISFactory implements
|
static class ISFactory implements
|
||||||
InviteeSessionStateFactory<Blog, BlogInviteeSessionState> {
|
InviteeSessionStateFactory<Blog, BlogInviteeSessionState> {
|
||||||
@Override
|
@Override
|
||||||
@@ -275,9 +286,8 @@ class BlogSharingManagerImpl extends
|
|||||||
@Override
|
@Override
|
||||||
public BlogInvitationReceivedEvent build(
|
public BlogInvitationReceivedEvent build(
|
||||||
BlogInviteeSessionState localState) {
|
BlogInviteeSessionState localState) {
|
||||||
Blog blog = sFactory.parse(localState);
|
return new BlogInvitationReceivedEvent(localState.getContactId(),
|
||||||
ContactId contactId = localState.getContactId();
|
localState.getStorageId(), sFactory.parse(localState));
|
||||||
return new BlogInvitationReceivedEvent(blog, contactId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,21 +16,21 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
|
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_DESC;
|
||||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
|
|
||||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
|
import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
|
||||||
|
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
|
||||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_DESC_LENGTH;
|
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_DESC_LENGTH;
|
||||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_TITLE_LENGTH;
|
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_TITLE_LENGTH;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
|
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
|
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_ACCEPT;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
|
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_INVITATION;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
|
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;
|
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ class BlogSharingValidator extends BdfMessageValidator {
|
|||||||
d.put(TYPE, type);
|
d.put(TYPE, type);
|
||||||
d.put(SESSION_ID, id);
|
d.put(SESSION_ID, id);
|
||||||
d.put(LOCAL, false);
|
d.put(LOCAL, false);
|
||||||
d.put(TIME, m.getTimestamp());
|
d.put(TIMESTAMP, m.getTimestamp());
|
||||||
return new BdfMessageContext(d);
|
return new BdfMessageContext(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,9 @@ class ForumSharingManagerImpl extends
|
|||||||
"cd11a5d04dccd9e2931d6fc3df456313"
|
"cd11a5d04dccd9e2931d6fc3df456313"
|
||||||
+ "63bb3e9d9d0e9405fccdb051f41f5449"));
|
+ "63bb3e9d9d0e9405fccdb051f41f5449"));
|
||||||
|
|
||||||
private final ForumManager forumManager;
|
|
||||||
|
|
||||||
private final SFactory sFactory;
|
private final SFactory sFactory;
|
||||||
private final IFactory iFactory;
|
private final IFactory iFactory;
|
||||||
|
private final IMFactory imFactory;
|
||||||
private final ISFactory isFactory;
|
private final ISFactory isFactory;
|
||||||
private final SSFactory ssFactory;
|
private final SSFactory ssFactory;
|
||||||
private final IRFactory irFactory;
|
private final IRFactory irFactory;
|
||||||
@@ -63,10 +62,9 @@ class ForumSharingManagerImpl extends
|
|||||||
SecureRandom random) {
|
SecureRandom random) {
|
||||||
super(db, messageQueueManager, clientHelper, metadataParser,
|
super(db, messageQueueManager, clientHelper, metadataParser,
|
||||||
metadataEncoder, random, privateGroupFactory, clock);
|
metadataEncoder, random, privateGroupFactory, clock);
|
||||||
this.forumManager = forumManager;
|
|
||||||
|
|
||||||
sFactory = new SFactory(forumFactory, forumManager);
|
sFactory = new SFactory(forumFactory, forumManager);
|
||||||
iFactory = new IFactory();
|
iFactory = new IFactory();
|
||||||
|
imFactory = new IMFactory();
|
||||||
isFactory = new ISFactory();
|
isFactory = new ISFactory();
|
||||||
ssFactory = new SSFactory();
|
ssFactory = new SSFactory();
|
||||||
irFactory = new IRFactory(sFactory);
|
irFactory = new IRFactory(sFactory);
|
||||||
@@ -78,16 +76,6 @@ class ForumSharingManagerImpl extends
|
|||||||
return CLIENT_ID;
|
return CLIENT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ForumInvitationMessage createInvitationMessage(MessageId id,
|
|
||||||
ForumInvitation msg, ContactId contactId, boolean available,
|
|
||||||
long time, boolean local, boolean sent, boolean seen,
|
|
||||||
boolean read) {
|
|
||||||
return new ForumInvitationMessage(id, msg.getSessionId(), contactId,
|
|
||||||
msg.getForumName(), msg.getMessage(), available, time, local,
|
|
||||||
sent, seen, read);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ShareableFactory<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState> getSFactory() {
|
protected ShareableFactory<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState> getSFactory() {
|
||||||
return sFactory;
|
return sFactory;
|
||||||
@@ -98,6 +86,11 @@ class ForumSharingManagerImpl extends
|
|||||||
return iFactory;
|
return iFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InvitationMessageFactory<ForumInvitation, ForumInvitationMessage> getIMFactory() {
|
||||||
|
return imFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InviteeSessionStateFactory<Forum, ForumInviteeSessionState> getISFactory() {
|
protected InviteeSessionStateFactory<Forum, ForumInviteeSessionState> getISFactory() {
|
||||||
return isFactory;
|
return isFactory;
|
||||||
@@ -185,6 +178,20 @@ class ForumSharingManagerImpl extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class IMFactory implements
|
||||||
|
InvitationMessageFactory<ForumInvitation, ForumInvitationMessage> {
|
||||||
|
@Override
|
||||||
|
public ForumInvitationMessage build(MessageId id,
|
||||||
|
ForumInvitation msg, ContactId contactId,
|
||||||
|
boolean available, long time, boolean local, boolean sent,
|
||||||
|
boolean seen, boolean read) {
|
||||||
|
return new ForumInvitationMessage(id, msg.getSessionId(), contactId,
|
||||||
|
msg.getForumName(), msg.getMessage(), available, time,
|
||||||
|
local,
|
||||||
|
sent, seen, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class ISFactory implements
|
static class ISFactory implements
|
||||||
InviteeSessionStateFactory<Forum, ForumInviteeSessionState> {
|
InviteeSessionStateFactory<Forum, ForumInviteeSessionState> {
|
||||||
@Override
|
@Override
|
||||||
@@ -245,9 +252,8 @@ class ForumSharingManagerImpl extends
|
|||||||
@Override
|
@Override
|
||||||
public ForumInvitationReceivedEvent build(
|
public ForumInvitationReceivedEvent build(
|
||||||
ForumInviteeSessionState localState) {
|
ForumInviteeSessionState localState) {
|
||||||
Forum forum = sFactory.parse(localState);
|
return new ForumInvitationReceivedEvent(localState.getContactId(),
|
||||||
ContactId contactId = localState.getContactId();
|
localState.getStorageId(), sFactory.parse(localState));
|
||||||
return new ForumInvitationReceivedEvent(forum, contactId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,19 +14,20 @@ import org.briarproject.clients.BdfMessageValidator;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
|
||||||
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
|
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
|
||||||
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
|
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
|
import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
|
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_ACCEPT;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE;
|
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_INVITATION;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
|
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;
|
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
|
|
||||||
@@ -77,7 +78,8 @@ class ForumSharingValidator extends BdfMessageValidator {
|
|||||||
d.put(TYPE, type);
|
d.put(TYPE, type);
|
||||||
d.put(SESSION_ID, id);
|
d.put(SESSION_ID, id);
|
||||||
d.put(LOCAL, false);
|
d.put(LOCAL, false);
|
||||||
d.put(TIME, m.getTimestamp());
|
d.put(TIMESTAMP, m.getTimestamp());
|
||||||
|
d.put(READ, false);
|
||||||
return new BdfMessageContext(d);
|
return new BdfMessageContext(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.briarproject.sharing;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.sharing.InvitationMessage;
|
||||||
|
import org.briarproject.api.sharing.SharingMessage;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
public interface InvitationMessageFactory<I extends SharingMessage.Invitation, IM extends InvitationMessage> {
|
||||||
|
|
||||||
|
IM build(MessageId id, I msg, ContactId contactId, boolean available,
|
||||||
|
long time, boolean local, boolean sent, boolean seen, boolean read);
|
||||||
|
}
|
||||||
@@ -29,9 +29,11 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(InviteeEngine.class.getName());
|
Logger.getLogger(InviteeEngine.class.getName());
|
||||||
|
|
||||||
private final InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory;
|
private final InvitationReceivedEventFactory<IS, IR>
|
||||||
|
invitationReceivedEventFactory;
|
||||||
|
|
||||||
InviteeEngine(InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory) {
|
InviteeEngine(
|
||||||
|
InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory) {
|
||||||
this.invitationReceivedEventFactory = invitationReceivedEventFactory;
|
this.invitationReceivedEventFactory = invitationReceivedEventFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +46,8 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
InviteeSessionState.State nextState = currentState.next(action);
|
InviteeSessionState.State nextState = currentState.next(action);
|
||||||
localState.setState(nextState);
|
localState.setState(nextState);
|
||||||
|
|
||||||
if (action == InviteeSessionState.Action.LOCAL_ABORT && currentState != InviteeSessionState.State.ERROR) {
|
if (action == InviteeSessionState.Action.LOCAL_ABORT &&
|
||||||
|
currentState != InviteeSessionState.State.ERROR) {
|
||||||
return abortSession(currentState, localState);
|
return abortSession(currentState, localState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +61,8 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
List<BaseMessage> messages;
|
List<BaseMessage> messages;
|
||||||
List<Event> events = Collections.emptyList();
|
List<Event> events = Collections.emptyList();
|
||||||
|
|
||||||
if (action == InviteeSessionState.Action.LOCAL_ACCEPT || action == InviteeSessionState.Action.LOCAL_DECLINE) {
|
if (action == InviteeSessionState.Action.LOCAL_ACCEPT ||
|
||||||
|
action == InviteeSessionState.Action.LOCAL_DECLINE) {
|
||||||
BaseMessage msg;
|
BaseMessage msg;
|
||||||
if (action == InviteeSessionState.Action.LOCAL_ACCEPT) {
|
if (action == InviteeSessionState.Action.LOCAL_ACCEPT) {
|
||||||
localState.setTask(TASK_ADD_SHARED_SHAREABLE);
|
localState.setTask(TASK_ADD_SHARED_SHAREABLE);
|
||||||
@@ -72,14 +76,12 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
}
|
}
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, localState, msg);
|
||||||
}
|
} else if (action == InviteeSessionState.Action.LOCAL_LEAVE) {
|
||||||
else if (action == InviteeSessionState.Action.LOCAL_LEAVE) {
|
|
||||||
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE,
|
||||||
localState.getGroupId(), localState.getSessionId());
|
localState.getGroupId(), localState.getSessionId());
|
||||||
messages = Collections.singletonList(msg);
|
messages = Collections.singletonList(msg);
|
||||||
logLocalAction(currentState, localState, msg);
|
logLocalAction(currentState, localState, msg);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Unknown Local Action");
|
throw new IllegalArgumentException("Unknown Local Action");
|
||||||
}
|
}
|
||||||
return new StateUpdate<IS, BaseMessage>(false,
|
return new StateUpdate<IS, BaseMessage>(false,
|
||||||
@@ -95,7 +97,8 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
InviteeSessionState.State currentState = localState.getState();
|
InviteeSessionState.State currentState = localState.getState();
|
||||||
InviteeSessionState.Action action = InviteeSessionState.Action.getRemote(msg.getType());
|
InviteeSessionState.Action action =
|
||||||
|
InviteeSessionState.Action.getRemote(msg.getType());
|
||||||
InviteeSessionState.State nextState = currentState.next(action);
|
InviteeSessionState.State nextState = currentState.next(action);
|
||||||
localState.setState(nextState);
|
localState.setState(nextState);
|
||||||
|
|
||||||
@@ -118,25 +121,25 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
deleteMsg = true;
|
deleteMsg = true;
|
||||||
}
|
}
|
||||||
// the sharer left the forum she had shared with us
|
// the sharer left the forum she had shared with us
|
||||||
else if (action == InviteeSessionState.Action.REMOTE_LEAVE && currentState == InviteeSessionState.State.FINISHED) {
|
else if (action == InviteeSessionState.Action.REMOTE_LEAVE &&
|
||||||
|
currentState == InviteeSessionState.State.FINISHED) {
|
||||||
localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_WITH_US);
|
localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_WITH_US);
|
||||||
}
|
} else if (currentState == InviteeSessionState.State.FINISHED) {
|
||||||
else if (currentState == InviteeSessionState.State.FINISHED) {
|
|
||||||
// ignore and delete messages coming in while in that state
|
// ignore and delete messages coming in while in that state
|
||||||
// note that LEAVE is possible, but was handled above
|
// note that LEAVE is possible, but was handled above
|
||||||
deleteMsg = true;
|
deleteMsg = true;
|
||||||
}
|
}
|
||||||
// the sharer left the forum before we couldn't even respond
|
// the sharer left the forum before we couldn't even respond
|
||||||
else if (action == InviteeSessionState.Action.REMOTE_LEAVE) {
|
else if (action == InviteeSessionState.Action.REMOTE_LEAVE) {
|
||||||
localState.setTask(TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US);
|
localState.setTask(
|
||||||
|
TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US);
|
||||||
}
|
}
|
||||||
// we have just received our invitation
|
// we have just received our invitation
|
||||||
else if (action == InviteeSessionState.Action.REMOTE_INVITATION) {
|
else if (action == InviteeSessionState.Action.REMOTE_INVITATION) {
|
||||||
localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US);
|
localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US);
|
||||||
Event event = invitationReceivedEventFactory.build(localState);
|
Event event = invitationReceivedEventFactory.build(localState);
|
||||||
events = Collections.singletonList(event);
|
events = Collections.singletonList(event);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Bad state");
|
throw new IllegalArgumentException("Bad state");
|
||||||
}
|
}
|
||||||
return new StateUpdate<IS, BaseMessage>(deleteMsg,
|
return new StateUpdate<IS, BaseMessage>(deleteMsg,
|
||||||
@@ -162,7 +165,8 @@ public class InviteeEngine<IS extends InviteeSessionState, IR extends Invitation
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMessageReceived(InviteeSessionState.State currentState, InviteeSessionState.State nextState,
|
private void logMessageReceived(InviteeSessionState.State currentState,
|
||||||
|
InviteeSessionState.State nextState,
|
||||||
long type, BaseMessage msg) {
|
long type, BaseMessage msg) {
|
||||||
|
|
||||||
if (!LOG.isLoggable(INFO)) return;
|
if (!LOG.isLoggable(INFO)) return;
|
||||||
|
|||||||
@@ -31,11 +31,12 @@ import org.briarproject.api.sharing.SharingManager;
|
|||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.Group;
|
import org.briarproject.api.sync.Group;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.InvalidMessageException;
|
||||||
import org.briarproject.api.sync.Message;
|
import org.briarproject.api.sync.Message;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
import org.briarproject.api.sync.MessageStatus;
|
import org.briarproject.api.sync.MessageStatus;
|
||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.clients.BdfIncomingMessageHook;
|
import org.briarproject.clients.ReadableMessageManagerImpl;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -53,10 +54,11 @@ import java.util.logging.Logger;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.LOCAL;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.READ;
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID;
|
import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
|
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
|
||||||
import static org.briarproject.api.sharing.SharingConstants.READ;
|
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID;
|
import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US;
|
import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US;
|
||||||
@@ -76,7 +78,6 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_REMOVE_SHAREABL
|
|||||||
import static org.briarproject.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE;
|
import static org.briarproject.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US;
|
import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US;
|
import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.TIME;
|
|
||||||
import static org.briarproject.api.sharing.SharingConstants.TO_BE_SHARED_BY_US;
|
import static org.briarproject.api.sharing.SharingConstants.TO_BE_SHARED_BY_US;
|
||||||
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||||
import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
|
import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
|
||||||
@@ -84,14 +85,13 @@ import static org.briarproject.api.sharing.SharingMessage.Invitation;
|
|||||||
import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
|
import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
|
||||||
|
|
||||||
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM extends InvitationMessage, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
|
abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM extends InvitationMessage, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
|
||||||
extends BdfIncomingMessageHook
|
extends ReadableMessageManagerImpl
|
||||||
implements SharingManager<S, IM>, Client, AddContactHook,
|
implements SharingManager<S, IM>, Client, AddContactHook,
|
||||||
RemoveContactHook {
|
RemoveContactHook {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(SharingManagerImpl.class.getName());
|
Logger.getLogger(SharingManagerImpl.class.getName());
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
|
||||||
private final MessageQueueManager messageQueueManager;
|
private final MessageQueueManager messageQueueManager;
|
||||||
private final MetadataEncoder metadataEncoder;
|
private final MetadataEncoder metadataEncoder;
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
@@ -105,8 +105,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
SecureRandom random, PrivateGroupFactory privateGroupFactory,
|
SecureRandom random, PrivateGroupFactory privateGroupFactory,
|
||||||
Clock clock) {
|
Clock clock) {
|
||||||
|
|
||||||
super(clientHelper, metadataParser);
|
super(clientHelper, db, metadataParser);
|
||||||
this.db = db;
|
|
||||||
this.messageQueueManager = messageQueueManager;
|
this.messageQueueManager = messageQueueManager;
|
||||||
this.metadataEncoder = metadataEncoder;
|
this.metadataEncoder = metadataEncoder;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
@@ -117,14 +116,12 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
|
|
||||||
public abstract ClientId getClientId();
|
public abstract ClientId getClientId();
|
||||||
|
|
||||||
protected abstract IM createInvitationMessage(MessageId id, I msg,
|
|
||||||
ContactId contactId, boolean available, long time, boolean local,
|
|
||||||
boolean sent, boolean seen, boolean read);
|
|
||||||
|
|
||||||
protected abstract ShareableFactory<S, I, IS, SS> getSFactory();
|
protected abstract ShareableFactory<S, I, IS, SS> getSFactory();
|
||||||
|
|
||||||
protected abstract InvitationFactory<I, SS> getIFactory();
|
protected abstract InvitationFactory<I, SS> getIFactory();
|
||||||
|
|
||||||
|
protected abstract InvitationMessageFactory<I, IM> getIMFactory();
|
||||||
|
|
||||||
protected abstract InviteeSessionStateFactory<S, IS> getISFactory();
|
protected abstract InviteeSessionStateFactory<S, IS> getISFactory();
|
||||||
|
|
||||||
protected abstract SharerSessionStateFactory<S, SS> getSSFactory();
|
protected abstract SharerSessionStateFactory<S, SS> getSSFactory();
|
||||||
@@ -186,8 +183,9 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void incomingMessage(Transaction txn, Message m, BdfList body,
|
protected void incomingReadableMessage(Transaction txn, Message m,
|
||||||
BdfDictionary d) throws DbException, FormatException {
|
BdfList body, BdfDictionary d)
|
||||||
|
throws DbException, FormatException, InvalidMessageException {
|
||||||
|
|
||||||
BaseMessage msg = BaseMessage.from(getIFactory(), m.getGroupId(), d);
|
BaseMessage msg = BaseMessage.from(getIFactory(), m.getGroupId(), d);
|
||||||
SessionId sessionId = msg.getSessionId();
|
SessionId sessionId = msg.getSessionId();
|
||||||
@@ -223,6 +221,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
deleteMessage(txn, m.getId());
|
deleteMessage(txn, m.getId());
|
||||||
|
throw new InvalidMessageException();
|
||||||
}
|
}
|
||||||
} else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT ||
|
} else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT ||
|
||||||
msg.getType() == SHARE_MSG_TYPE_DECLINE) {
|
msg.getType() == SHARE_MSG_TYPE_DECLINE) {
|
||||||
@@ -341,26 +340,10 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) {
|
||||||
BdfDictionary d = m.getValue();
|
BdfDictionary d = m.getValue();
|
||||||
try {
|
try {
|
||||||
I msg = getIFactory().build(group.getId(), d);
|
IM im = getInvitationMessage(txn, group.getId(), contactId,
|
||||||
MessageStatus status =
|
m.getKey(), d);
|
||||||
db.getMessageStatus(txn, contactId, m.getKey());
|
if (im != null)
|
||||||
long time = d.getLong(TIME);
|
list.add(im);
|
||||||
boolean local = d.getBoolean(LOCAL);
|
|
||||||
boolean read = d.getBoolean(READ, false);
|
|
||||||
boolean available = false;
|
|
||||||
if (!local) {
|
|
||||||
// figure out whether the shareable is still available
|
|
||||||
SharingSessionState s =
|
|
||||||
getSessionState(txn, msg.getSessionId(), true);
|
|
||||||
if (!(s instanceof InviteeSessionState))
|
|
||||||
continue;
|
|
||||||
available = ((InviteeSessionState) s).getState() ==
|
|
||||||
AWAIT_LOCAL_RESPONSE;
|
|
||||||
}
|
|
||||||
IM im = createInvitationMessage(m.getKey(), msg, contactId,
|
|
||||||
available, time, local, status.isSent(),
|
|
||||||
status.isSeen(), read);
|
|
||||||
list.add(im);
|
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -375,6 +358,50 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IM getInvitationMessage(ContactId contactId, MessageId messageId)
|
||||||
|
throws DbException {
|
||||||
|
Transaction txn = db.startTransaction(true);
|
||||||
|
try {
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
Group group = getContactGroup(contact);
|
||||||
|
|
||||||
|
BdfDictionary d =
|
||||||
|
clientHelper.getMessageMetadataAsDictionary(txn, messageId);
|
||||||
|
IM im = getInvitationMessage(txn, group.getId(), contactId,
|
||||||
|
messageId, d);
|
||||||
|
txn.setComplete();
|
||||||
|
return im;
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
} finally {
|
||||||
|
db.endTransaction(txn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IM getInvitationMessage(Transaction txn, GroupId groupId,
|
||||||
|
ContactId contactId, MessageId id, BdfDictionary d)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
I msg = getIFactory().build(groupId, d);
|
||||||
|
MessageStatus status =
|
||||||
|
db.getMessageStatus(txn, contactId, id);
|
||||||
|
long time = d.getLong(TIMESTAMP);
|
||||||
|
boolean local = d.getBoolean(LOCAL);
|
||||||
|
boolean read = d.getBoolean(READ, false);
|
||||||
|
boolean available = false;
|
||||||
|
if (!local) {
|
||||||
|
// figure out whether the shareable is still available
|
||||||
|
SharingSessionState s =
|
||||||
|
getSessionState(txn, msg.getSessionId(), true);
|
||||||
|
if (!(s instanceof InviteeSessionState))
|
||||||
|
return null;
|
||||||
|
available = ((InviteeSessionState) s).getState() ==
|
||||||
|
AWAIT_LOCAL_RESPONSE;
|
||||||
|
}
|
||||||
|
return getIMFactory().build(id, msg, contactId, available, time, local,
|
||||||
|
status.isSent(), status.isSeen(), read);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<S> getInvited() throws DbException {
|
public Collection<S> getInvited() throws DbException {
|
||||||
Transaction txn = db.startTransaction(true);
|
Transaction txn = db.startTransaction(true);
|
||||||
@@ -840,14 +867,16 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
// add message itself as metadata
|
// add message itself as metadata
|
||||||
BdfDictionary d = m.toBdfDictionary();
|
BdfDictionary d = m.toBdfDictionary();
|
||||||
d.put(LOCAL, true);
|
d.put(LOCAL, true);
|
||||||
d.put(TIME, timestamp);
|
d.put(TIMESTAMP, timestamp);
|
||||||
Metadata meta = metadataEncoder.encode(d);
|
Metadata meta = metadataEncoder.encode(d);
|
||||||
|
|
||||||
messageQueueManager
|
messageQueueManager
|
||||||
.sendMessage(txn, group, timestamp, body, meta);
|
.sendMessage(txn, group, timestamp, body, meta);
|
||||||
|
updateGroupMetadata(txn, m.getGroupId(), timestamp, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Group getContactGroup(Contact c) {
|
@Override
|
||||||
|
protected Group getContactGroup(Contact c) {
|
||||||
return privateGroupFactory.createPrivateGroup(getClientId(), c);
|
return privateGroupFactory.createPrivateGroup(getClientId(), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,8 +951,8 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void storeShareableList(Transaction txn, GroupId groupId,
|
private void storeShareableList(Transaction txn, GroupId groupId,
|
||||||
String key,
|
String key, List<S> shareables)
|
||||||
List<S> shareables) throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
|
|
||||||
BdfList list = encodeShareableList(shareables);
|
BdfList list = encodeShareableList(shareables);
|
||||||
BdfDictionary metadata = BdfDictionary.of(
|
BdfDictionary metadata = BdfDictionary.of(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.TestUtils;
|
|||||||
import org.briarproject.api.Bytes;
|
import org.briarproject.api.Bytes;
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.clients.ClientHelper;
|
import org.briarproject.api.clients.ClientHelper;
|
||||||
|
import org.briarproject.api.clients.SessionId;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
import org.briarproject.api.contact.ContactManager;
|
||||||
@@ -19,7 +20,6 @@ import org.briarproject.api.identity.Author;
|
|||||||
import org.briarproject.api.identity.AuthorFactory;
|
import org.briarproject.api.identity.AuthorFactory;
|
||||||
import org.briarproject.api.identity.AuthorId;
|
import org.briarproject.api.identity.AuthorId;
|
||||||
import org.briarproject.api.introduction.IntroduceeProtocolState;
|
import org.briarproject.api.introduction.IntroduceeProtocolState;
|
||||||
import org.briarproject.api.clients.SessionId;
|
|
||||||
import org.briarproject.api.properties.TransportPropertyManager;
|
import org.briarproject.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
import org.briarproject.api.sync.Group;
|
import org.briarproject.api.sync.Group;
|
||||||
@@ -34,6 +34,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST;
|
import static org.briarproject.api.introduction.IntroduceeProtocolState.AWAIT_REQUEST;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
import static org.briarproject.api.introduction.IntroductionConstants.ACCEPT;
|
||||||
@@ -46,7 +47,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
|||||||
import static org.briarproject.api.introduction.IntroductionConstants.INTRODUCER;
|
import static org.briarproject.api.introduction.IntroductionConstants.INTRODUCER;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.LOCAL_AUTHOR_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
|
import static org.briarproject.api.introduction.IntroductionConstants.NOT_OUR_RESPONSE;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
||||||
@@ -63,7 +63,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
|
|||||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||||
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
public class IntroduceeManagerTest extends BriarTestCase {
|
public class IntroduceeManagerTest extends BriarTestCase {
|
||||||
@@ -164,7 +163,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
|||||||
msg.put(GROUP_ID, introductionGroup1.getId());
|
msg.put(GROUP_ID, introductionGroup1.getId());
|
||||||
msg.put(SESSION_ID, sessionId);
|
msg.put(SESSION_ID, sessionId);
|
||||||
msg.put(MESSAGE_ID, message1.getId());
|
msg.put(MESSAGE_ID, message1.getId());
|
||||||
msg.put(MESSAGE_TIME, time);
|
msg.put(TIMESTAMP, time);
|
||||||
msg.put(NAME, introducee2.getAuthor().getName());
|
msg.put(NAME, introducee2.getAuthor().getName());
|
||||||
msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
||||||
|
|
||||||
@@ -192,7 +191,7 @@ public class IntroduceeManagerTest extends BriarTestCase {
|
|||||||
msg.put(GROUP_ID, introductionGroup1.getId());
|
msg.put(GROUP_ID, introductionGroup1.getId());
|
||||||
msg.put(SESSION_ID, sessionId);
|
msg.put(SESSION_ID, sessionId);
|
||||||
msg.put(MESSAGE_ID, message1.getId());
|
msg.put(MESSAGE_ID, message1.getId());
|
||||||
msg.put(MESSAGE_TIME, time);
|
msg.put(TIMESTAMP, time);
|
||||||
msg.put(NAME, introducee2.getAuthor().getName());
|
msg.put(NAME, introducee2.getAuthor().getName());
|
||||||
msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
msg.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import static org.briarproject.api.clients.ReadableMessageConstants.TIMESTAMP;
|
||||||
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.introduction.IntroducerProtocolState.AWAIT_RESPONSES;
|
import static org.briarproject.api.introduction.IntroducerProtocolState.AWAIT_RESPONSES;
|
||||||
import static org.briarproject.api.introduction.IntroducerProtocolState.PREPARE_REQUESTS;
|
import static org.briarproject.api.introduction.IntroducerProtocolState.PREPARE_REQUESTS;
|
||||||
@@ -39,7 +40,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.CONTACT_ID
|
|||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
||||||
import static org.briarproject.api.introduction.IntroductionConstants.ROLE;
|
import static org.briarproject.api.introduction.IntroductionConstants.ROLE;
|
||||||
@@ -136,7 +136,7 @@ public class IntroducerManagerTest extends BriarTestCase {
|
|||||||
msg1.put(NAME, state.getString(CONTACT_2));
|
msg1.put(NAME, state.getString(CONTACT_2));
|
||||||
msg1.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
msg1.put(PUBLIC_KEY, introducee2.getAuthor().getPublicKey());
|
||||||
final BdfDictionary msg1send = (BdfDictionary) msg1.clone();
|
final BdfDictionary msg1send = (BdfDictionary) msg1.clone();
|
||||||
msg1send.put(MESSAGE_TIME, time);
|
msg1send.put(TIMESTAMP, time);
|
||||||
|
|
||||||
final BdfDictionary msg2 = new BdfDictionary();
|
final BdfDictionary msg2 = new BdfDictionary();
|
||||||
msg2.put(TYPE, TYPE_REQUEST);
|
msg2.put(TYPE, TYPE_REQUEST);
|
||||||
@@ -145,7 +145,7 @@ public class IntroducerManagerTest extends BriarTestCase {
|
|||||||
msg2.put(NAME, state.getString(CONTACT_1));
|
msg2.put(NAME, state.getString(CONTACT_1));
|
||||||
msg2.put(PUBLIC_KEY, introducee1.getAuthor().getPublicKey());
|
msg2.put(PUBLIC_KEY, introducee1.getAuthor().getPublicKey());
|
||||||
final BdfDictionary msg2send = (BdfDictionary) msg2.clone();
|
final BdfDictionary msg2send = (BdfDictionary) msg2.clone();
|
||||||
msg2send.put(MESSAGE_TIME, time);
|
msg2send.put(TIMESTAMP, time);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// initialize and store session state
|
// initialize and store session state
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
introductionManager
|
introductionManager
|
||||||
.incomingMessage(txn, message1, new BdfList(), msg);
|
.incomingReadableMessage(txn, message1, new BdfList(), msg);
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
assertFalse(txn.isComplete());
|
assertFalse(txn.isComplete());
|
||||||
@@ -277,7 +277,7 @@ public class IntroductionManagerImplTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
introductionManager
|
introductionManager
|
||||||
.incomingMessage(txn, message1, new BdfList(), msg);
|
.incomingReadableMessage(txn, message1, new BdfList(), msg);
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
assertFalse(txn.isComplete());
|
assertFalse(txn.isComplete());
|
||||||
|
|||||||
Reference in New Issue
Block a user