Use group metadata from ConversationManager for showing contact lists

Fixes #373
This commit is contained in:
Torsten Grote
2016-10-05 12:14:40 -03:00
parent 48a3db46bc
commit 70d39d03bc
11 changed files with 88 additions and 207 deletions

View File

@@ -30,6 +30,7 @@ import org.briarproject.api.keyagreement.PayloadEncoder;
import org.briarproject.api.keyagreement.PayloadParser;
import org.briarproject.api.lifecycle.IoExecutor;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.plugins.ConnectionRegistry;
@@ -86,6 +87,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
ContactManager contactManager();
ConversationManager conversationManager();
MessagingManager messagingManager();
PrivateMessageFactory privateMessageFactory();

View File

@@ -96,8 +96,10 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
int count = getItemCount();
for (int i = 0; i < count; i++) {
ContactListItem item = getItemAt(i);
if (item != null && item.getGroupId().equals(g))
if (item != null && item.getGroupId() != null &&
item.getGroupId().equals(g)) {
return i;
}
}
return INVALID_POSITION; // Not found
}

View File

@@ -35,7 +35,7 @@ public class ContactListAdapter
if (item == null) return;
// unread count
int unread = item.getUnreadCount();
long unread = item.getUnreadCount();
if (unread > 0) {
ui.unread.setText(String.valueOf(unread));
ui.unread.setVisibility(View.VISIBLE);

View File

@@ -21,13 +21,12 @@ import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.keyagreement.KeyAgreementActivity;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchContactException;
import org.briarproject.api.event.ContactAddedEvent;
import org.briarproject.api.event.ContactConnectedEvent;
import org.briarproject.api.event.ContactDisconnectedEvent;
import org.briarproject.api.event.ContactRemovedEvent;
@@ -40,21 +39,18 @@ import org.briarproject.api.event.IntroductionResponseReceivedEvent;
import org.briarproject.api.event.InvitationReceivedEvent;
import org.briarproject.api.event.InvitationResponseReceivedEvent;
import org.briarproject.api.event.PrivateMessageReceivedEvent;
import org.briarproject.api.forum.ForumSharingManager;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.introduction.IntroductionMessage;
import org.briarproject.api.introduction.IntroductionRequest;
import org.briarproject.api.introduction.IntroductionResponse;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
@@ -88,13 +84,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
@Inject
protected volatile IdentityManager identityManager;
@Inject
protected volatile MessagingManager messagingManager;
@Inject
protected volatile IntroductionManager introductionManager;
@Inject
protected volatile ForumSharingManager forumSharingManager;
@Inject
protected volatile BlogSharingManager blogSharingManager;
protected volatile ConversationManager conversationManager;
public static ContactListFragment newInstance() {
@@ -130,8 +120,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
new ContactListAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, ContactListItem item) {
GroupId groupId = item.getGroupId();
if (groupId == null) return;
Intent i = new Intent(getActivity(),
ConversationActivity.class);
i.putExtra(GROUP_ID, groupId.getBytes());
@@ -215,15 +205,15 @@ public class ContactListFragment extends BaseFragment implements EventListener {
try {
ContactId id = c.getId();
GroupId groupId =
messagingManager.getConversationId(id);
Collection<ConversationItem> messages =
getMessages(id);
conversationManager.getConversationId(id);
GroupCount count =
conversationManager.getGroupCount(id);
boolean connected =
connectionRegistry.isConnected(c.getId());
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
contacts.add(new ContactListItem(c, localAuthor,
connected, groupId, messages));
connected, groupId, count));
} catch (NoSuchContactException e) {
// Continue
}
@@ -252,14 +242,9 @@ public class ContactListFragment extends BaseFragment implements EventListener {
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactAddedEvent) {
if (((ContactAddedEvent) e).isActive()) {
LOG.info("Contact added as active, reloading");
loadContacts();
}
} else if (e instanceof ContactStatusChangedEvent) {
if (e instanceof ContactStatusChangedEvent) {
LOG.info("Contact Status changed, reloading");
// TODO We can update the contact state without needing to reload
// is also broadcast when contact was added
loadContacts();
} else if (e instanceof ContactConnectedEvent) {
setConnected(((ContactConnectedEvent) e).getContactId(), true);
@@ -286,49 +271,19 @@ public class ContactListFragment extends BaseFragment implements EventListener {
IntroductionResponse ir = m.getIntroductionResponse();
updateItem(m.getContactId(), ConversationItem.from(ir));
} else if (e instanceof InvitationReceivedEvent) {
LOG.info("Invitation received, reloading conversation...");
LOG.info("Invitation Request received, update contact");
InvitationReceivedEvent m = (InvitationReceivedEvent) e;
reloadConversation(m.getContactId());
InvitationRequest ir = m.getRequest();
updateItem(m.getContactId(), ConversationItem.from(ir));
} else if (e instanceof InvitationResponseReceivedEvent) {
LOG.info("Invitation Response received, reloading ...");
LOG.info("Invitation Response received, update contact");
InvitationResponseReceivedEvent m =
(InvitationResponseReceivedEvent) e;
reloadConversation(m.getContactId());
InvitationResponse ir = m.getResponse();
updateItem(m.getContactId(), ConversationItem.from(ir));
}
}
private void reloadConversation(final ContactId c) {
listener.runOnDbThread(new Runnable() {
@Override
public void run() {
try {
Collection<ConversationItem> messages = getMessages(c);
updateItem(c, messages);
} catch (NoSuchContactException e) {
LOG.info("Contact removed");
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
private void updateItem(final ContactId c,
final Collection<ConversationItem> messages) {
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
int position = adapter.findItemPosition(c);
ContactListItem item = adapter.getItemAt(position);
if (item != null) {
item.setMessages(messages);
adapter.updateItemAt(position, item);
}
}
});
}
private void updateItem(final ContactId c, final ConversationItem m) {
listener.runOnUiThread(new Runnable() {
@Override
@@ -382,50 +337,4 @@ public class ContactListFragment extends BaseFragment implements EventListener {
});
}
// This needs to be called from the DB thread
// Do not call getActivty() here as it might return null
private Collection<ConversationItem> getMessages(ContactId id)
throws DbException {
long now = System.currentTimeMillis();
Collection<ConversationItem> messages = new ArrayList<>();
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(id);
for (PrivateMessageHeader h : headers) {
messages.add(ConversationItem.from(h));
}
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading message headers took " + duration + " ms");
now = System.currentTimeMillis();
Collection<IntroductionMessage> introductions =
introductionManager
.getIntroductionMessages(id);
for (IntroductionMessage m : introductions) {
messages.add(ConversationItem.from(m));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading introduction messages took " + duration + " ms");
now = System.currentTimeMillis();
Collection<InvitationMessage> forumInvitations =
forumSharingManager.getInvitationMessages(id);
for (InvitationMessage i : forumInvitations) {
messages.add(ConversationItem.from(i));
}
Collection<InvitationMessage> blogInvitations =
blogSharingManager.getInvitationMessages(id);
for (InvitationMessage i : blogInvitations) {
messages.add(ConversationItem.from(i));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading invitations took " + duration + " ms");
return messages;
}
}

View File

@@ -1,14 +1,15 @@
package org.briarproject.android.contact;
import android.support.annotation.Nullable;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.GroupId;
import java.util.Collection;
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
// This class is not thread-safe
// This class is NOT thread-safe
public class ContactListItem {
private final Contact contact;
@@ -16,28 +17,17 @@ public class ContactListItem {
private final GroupId groupId;
private boolean connected, empty;
private long timestamp;
private int unread;
private long unread;
public ContactListItem(Contact contact, LocalAuthor localAuthor,
boolean connected,
GroupId groupId,
Collection<ConversationItem> messages) {
boolean connected, @Nullable GroupId groupId, GroupCount count) {
this.contact = contact;
this.localAuthor = localAuthor;
this.groupId = groupId;
this.connected = connected;
setMessages(messages);
}
void setMessages(Collection<ConversationItem> messages) {
empty = messages == null || messages.isEmpty();
timestamp = 0;
unread = 0;
if (!empty) {
for (ConversationItem i : messages) {
addMessage(i);
}
}
this.empty = count.getMsgCount() == 0;
this.unread = count.getUnreadCount();
this.timestamp = count.getLatestMsgTime();
}
void addMessage(ConversationItem message) {
@@ -58,6 +48,7 @@ public class ContactListItem {
return localAuthor;
}
@Nullable
GroupId getGroupId() {
return groupId;
}
@@ -78,7 +69,7 @@ public class ContactListItem {
return timestamp;
}
int getUnreadCount() {
long getUnreadCount() {
return unread;
}
}

View File

@@ -34,6 +34,7 @@ import org.briarproject.android.view.TextInputView;
import org.briarproject.android.view.TextInputView.TextInputListener;
import org.briarproject.api.FormatException;
import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.BaseMessageHeader;
import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
@@ -476,28 +477,27 @@ public class ConversationActivity extends BriarActivity
}
private void markMessagesRead() {
List<MessageId> unread = new ArrayList<>();
Map<MessageId, GroupId> unread = new HashMap<>();
SparseArray<IncomingItem> list = adapter.getIncomingMessages();
for (int i = 0; i < list.size(); i++) {
IncomingItem item = list.valueAt(i);
if (!item.isRead()) unread.add(item.getId());
if (!item.isRead()) unread.put(item.getId(), item.getGroupId());
}
if (unread.isEmpty()) return;
if (LOG.isLoggable(INFO))
LOG.info("Marking " + unread.size() + " messages read");
markMessagesRead(Collections.unmodifiableList(unread));
markMessagesRead(Collections.unmodifiableMap(unread));
}
private void markMessagesRead(final Collection<MessageId> unread) {
private void markMessagesRead(final Map<MessageId, GroupId> unread) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
long now = System.currentTimeMillis();
for (MessageId m : unread)
// not really clean, but the messaging manager can
// handle introduction messages as well
messagingManager.setReadFlag(groupId, m, true);
for (Map.Entry<MessageId, GroupId> e : unread.entrySet())
messagingManager
.setReadFlag(e.getValue(), e.getKey(), true);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Marking read took " + duration + " ms");
@@ -560,6 +560,7 @@ public class ConversationActivity extends BriarActivity
IntroductionRequest ir = event.getIntroductionRequest();
ConversationItem item = new ConversationIntroductionInItem(ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof IntroductionResponseReceivedEvent) {
IntroductionResponseReceivedEvent event =
@@ -570,25 +571,33 @@ public class ConversationActivity extends BriarActivity
ConversationItem item =
ConversationItem.from(this, contactName, ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof InvitationReceivedEvent) {
InvitationReceivedEvent event =
(InvitationReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation received, reloading...");
loadMessages();
LOG.info("Invitation received, adding...");
InvitationRequest ir = event.getRequest();
ConversationItem item = ConversationItem.from(ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
} else if (e instanceof InvitationResponseReceivedEvent) {
InvitationResponseReceivedEvent event =
(InvitationResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation response received, reloading...");
loadMessages();
LOG.info("Invitation response received, adding...");
InvitationResponse ir = event.getResponse();
ConversationItem item =
ConversationItem.from(this, contactName, ir);
addConversationItem(item);
markMessageReadIfNew(ir);
}
}
}
private void markMessageReadIfNew(final PrivateMessageHeader h) {
private void markMessageReadIfNew(final BaseMessageHeader h) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -597,22 +606,23 @@ public class ConversationActivity extends BriarActivity
// Mark the message read if it's the newest message
long lastMsgTime = item.getTime();
long newMsgTime = h.getTimestamp();
if (newMsgTime > lastMsgTime) markNewMessageRead(h.getId());
if (newMsgTime > lastMsgTime)
markNewMessageRead(h.getGroupId(), h.getId());
else loadMessages();
} else {
// mark the message as read as well if it is the first one
markNewMessageRead(h.getId());
markNewMessageRead(h.getGroupId(), h.getId());
}
}
});
}
private void markNewMessageRead(final MessageId m) {
private void markNewMessageRead(final GroupId g, final MessageId m) {
runOnDbThread(new Runnable() {
@Override
public void run() {
try {
messagingManager.setReadFlag(groupId, m, true);
messagingManager.setReadFlag(g, m, true);
loadMessages();
} catch (DbException e) {
if (LOG.isLoggable(WARNING))

View File

@@ -5,6 +5,7 @@ import org.briarproject.api.forum.ForumPostHeader;
import java.util.Collection;
// This class is NOT thread-safe
class ForumListItem {
private final Forum forum;

View File

@@ -15,9 +15,9 @@ import org.briarproject.R;
import org.briarproject.android.ActivityComponent;
import org.briarproject.android.contact.ContactListAdapter;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.contact.ConversationItem;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
@@ -25,21 +25,16 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.introduction.IntroductionManager;
import org.briarproject.api.introduction.IntroductionMessage;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.messaging.ConversationManager;
import org.briarproject.api.plugins.ConnectionRegistry;
import org.briarproject.api.sync.GroupId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
public class ContactChooserFragment extends BaseFragment {
@@ -61,9 +56,7 @@ public class ContactChooserFragment extends BaseFragment {
@Inject
protected volatile IdentityManager identityManager;
@Inject
protected volatile MessagingManager messagingManager;
@Inject
protected volatile IntroductionManager introductionManager;
protected volatile ConversationManager conversationManager;
@Inject
protected volatile ConnectionRegistry connectionRegistry;
@@ -159,23 +152,23 @@ public class ContactChooserFragment extends BaseFragment {
public void run() {
try {
List<ContactListItem> contacts = new ArrayList<>();
AuthorId localAuthorId = null;
AuthorId localAuthorId =
identityManager.getLocalAuthor().getId();
for (Contact c : contactManager.getActiveContacts()) {
if (c.getId().getInt() == contactId) {
c1 = c;
localAuthorId = c1.getLocalAuthorId();
} else {
ContactId id = c.getId();
GroupId groupId =
messagingManager.getConversationId(id);
Collection<ConversationItem> messages =
getMessages(id);
conversationManager.getConversationId(id);
GroupCount count =
conversationManager.getGroupCount(id);
boolean connected =
connectionRegistry.isConnected(c.getId());
LocalAuthor localAuthor = identityManager
.getLocalAuthor(c.getLocalAuthorId());
contacts.add(new ContactListItem(c, localAuthor,
connected, groupId, messages));
connected, groupId, count));
}
}
displayContacts(localAuthorId, contacts);
@@ -220,36 +213,4 @@ public class ContactChooserFragment extends BaseFragment {
builder.show();
}
/**
* This needs to be called from the DbThread
*/
private Collection<ConversationItem> getMessages(ContactId id)
throws DbException {
long now = System.currentTimeMillis();
Collection<ConversationItem> messages = new ArrayList<>();
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(id);
for (PrivateMessageHeader h : headers) {
messages.add(ConversationItem.from(h));
}
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading message headers took " + duration + " ms");
now = System.currentTimeMillis();
Collection<IntroductionMessage> introductions =
introductionManager
.getIntroductionMessages(id);
for (IntroductionMessage m : introductions) {
messages.add(ConversationItem.from(m));
}
duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading introduction messages took " + duration + " ms");
return messages;
}
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.android.sharing;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.transition.Fade;
import android.view.LayoutInflater;
@@ -39,6 +40,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIntegers;
import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
public class ContactSelectorFragment extends BaseFragment implements
@@ -122,8 +124,9 @@ public class ContactSelectorFragment extends BaseFragment implements
if (savedInstanceState != null) {
ArrayList<Integer> intContacts =
savedInstanceState.getIntegerArrayList(CONTACTS);
selectedContacts = ShareActivity.getContactsFromIntegers(
intContacts);
if (intContacts != null) {
selectedContacts = getContactsFromIntegers(intContacts);
}
}
return contentView;
@@ -185,7 +188,7 @@ public class ContactSelectorFragment extends BaseFragment implements
updateMenuItem();
}
private void loadContacts(final Collection<ContactId> selection) {
private void loadContacts(@Nullable final Collection<ContactId> selection) {
shareActivity.runOnDbThread(new Runnable() {
@Override
public void run() {

View File

@@ -1,14 +1,14 @@
package org.briarproject.android.sharing;
import android.support.annotation.UiThread;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.contact.ConversationItem;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.GroupId;
import java.util.Collections;
// This class is not thread-safe
// This class is NOT thread-safe
public class SelectableContactListItem extends ContactListItem {
private boolean selected, disabled;
@@ -16,8 +16,7 @@ public class SelectableContactListItem extends ContactListItem {
public SelectableContactListItem(Contact contact, LocalAuthor localAuthor,
GroupId groupId, boolean selected, boolean disabled) {
super(contact, localAuthor, false, groupId,
Collections.<ConversationItem>emptyList());
super(contact, localAuthor, false, groupId, new GroupCount(0, 0, 0));
this.selected = selected;
this.disabled = disabled;

View File

@@ -9,6 +9,8 @@ import org.briarproject.R;
import org.briarproject.android.BriarActivity;
import org.briarproject.android.contact.ContactListItem;
import org.briarproject.android.view.BriarRecyclerView;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.db.DbException;
import org.briarproject.api.identity.IdentityManager;
@@ -106,7 +108,7 @@ abstract class SharingStatusActivity extends BriarActivity {
.getLocalAuthor(c.getLocalAuthorId());
ContactListItem item =
new ContactListItem(c, localAuthor, false, null,
null);
new GroupCount(0, 0, 0));
contactItems.add(item);
}
} catch (DbException e) {
@@ -142,7 +144,7 @@ abstract class SharingStatusActivity extends BriarActivity {
.getLocalAuthor(c.getLocalAuthorId());
ContactListItem item =
new ContactListItem(c, localAuthor, false, null,
null);
new GroupCount(0, 0, 0));
contactItems.add(item);
}
} catch (DbException e) {