Merge branch 'conversation-manager' into 'master'

Use ConversationManager for private message retrieval

See merge request briar/briar!912
This commit is contained in:
akwizgran
2018-09-20 13:01:53 +00:00
74 changed files with 983 additions and 1497 deletions

View File

@@ -41,13 +41,9 @@ import org.briarproject.briar.android.util.BriarNotificationBuilder;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.Set;
import java.util.concurrent.Callable;
@@ -235,19 +231,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
} else if (e instanceof BlogPostAddedEvent) {
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
showBlogPostNotification(b.getGroupId());
} else if (e instanceof IntroductionRequestReceivedEvent) {
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof IntroductionResponseReceivedEvent) {
ContactId c =
((IntroductionResponseReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof InvitationRequestReceivedEvent) {
ContactId c = ((InvitationRequestReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof InvitationResponseReceivedEvent) {
ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();
showContactNotification(c);
} else if (e instanceof IntroductionSucceededEvent) {
showIntroductionNotification();
}

View File

@@ -21,11 +21,11 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogSharingManager;
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
import java.util.ArrayList;
@@ -107,7 +107,7 @@ class BlogControllerImpl extends BaseControllerImpl
} else if (e instanceof BlogInvitationResponseReceivedEvent) {
BlogInvitationResponseReceivedEvent b =
(BlogInvitationResponseReceivedEvent) e;
InvitationResponse r = b.getResponse();
BlogInvitationResponse r = b.getMessageHeader();
if (r.getShareableId().equals(groupId) && r.wasAccepted()) {
LOG.info("Blog invitation accepted");
onBlogInvitationAccepted(b.getContactId());

View File

@@ -36,19 +36,10 @@ import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
import org.briarproject.briar.android.view.BriarRecyclerView;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import java.util.ArrayList;
import java.util.List;
@@ -256,40 +247,16 @@ public class ContactListFragment extends BaseFragment implements EventListener {
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
PrivateMessageHeader h = p.getMessageHeader();
updateItem(p.getContactId(), h);
} else if (e instanceof IntroductionRequestReceivedEvent) {
LOG.info("Introduction request received, updating item");
IntroductionRequestReceivedEvent m =
(IntroductionRequestReceivedEvent) e;
IntroductionRequest ir = m.getIntroductionRequest();
updateItem(m.getContactId(), ir);
} else if (e instanceof IntroductionResponseReceivedEvent) {
LOG.info("Introduction response received, updating item");
IntroductionResponseReceivedEvent m =
(IntroductionResponseReceivedEvent) e;
IntroductionResponse ir = m.getIntroductionResponse();
updateItem(m.getContactId(), ir);
} else if (e instanceof InvitationRequestReceivedEvent) {
LOG.info("Invitation Request received, update item");
InvitationRequestReceivedEvent m =
(InvitationRequestReceivedEvent) e;
InvitationRequest ir = m.getRequest();
updateItem(m.getContactId(), ir);
} else if (e instanceof InvitationResponseReceivedEvent) {
LOG.info("Invitation response received, updating item");
InvitationResponseReceivedEvent m =
(InvitationResponseReceivedEvent) e;
InvitationResponse ir = m.getResponse();
updateItem(m.getContactId(), ir);
}
}
private void updateItem(ContactId c, BaseMessageHeader h) {
private void updateItem(ContactId c, PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision();
int position = adapter.findItemPosition(c);
ContactListItem item = adapter.getItemAt(position);
if (item != null) {
ConversationItem i = ConversationItem.from(getContext(), h);
ConversationItem i = ConversationItem.from(getContext(), "", h);
item.addMessage(i);
adapter.updateItemAt(position, item);
}

View File

@@ -1,8 +1,11 @@
package org.briarproject.briar.android.contact;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
@@ -62,24 +65,15 @@ import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.forum.ForumSharingManager;
import org.briarproject.briar.api.introduction.IntroductionManager;
import org.briarproject.briar.api.introduction.IntroductionMessage;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
import org.briarproject.briar.api.messaging.ConversationManager;
import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.briarproject.briar.api.sharing.InvitationMessage;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
import org.thoughtcrime.securesms.components.util.FutureTaskListener;
import org.thoughtcrime.securesms.components.util.ListenableFutureTask;
import java.util.ArrayList;
import java.util.Collection;
@@ -87,13 +81,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import de.hdodenhof.circleimageview.CircleImageView;
@@ -138,6 +129,7 @@ public class ConversationActivity extends BriarActivity
Executor cryptoExecutor;
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
private final MutableLiveData<String> contactName = new MutableLiveData<>();
private ConversationAdapter adapter;
private Toolbar toolbar;
@@ -147,24 +139,14 @@ public class ConversationActivity extends BriarActivity
private BriarRecyclerView list;
private TextInputView textInputView;
private final ListenableFutureTask<String> contactNameTask =
new ListenableFutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Contact c = contactManager.getContact(contactId);
contactName = c.getAuthor().getName();
return c.getAuthor().getName();
}
});
private final AtomicBoolean contactNameTaskStarted =
new AtomicBoolean(false);
// Fields that are accessed from background threads must be volatile
@Inject
volatile ContactManager contactManager;
@Inject
volatile MessagingManager messagingManager;
@Inject
volatile ConversationManager conversationManager;
@Inject
volatile EventBus eventBus;
@Inject
volatile SettingsManager settingsManager;
@@ -181,8 +163,6 @@ public class ConversationActivity extends BriarActivity
private volatile ContactId contactId;
@Nullable
private volatile String contactName;
@Nullable
private volatile AuthorId contactAuthorId;
@Nullable
private volatile GroupId messagingGroupId;
@@ -294,9 +274,9 @@ public class ConversationActivity extends BriarActivity
runOnDbThread(() -> {
try {
long start = now();
if (contactName == null || contactAuthorId == null) {
if (contactAuthorId == null) {
Contact contact = contactManager.getContact(contactId);
contactName = contact.getAuthor().getName();
contactName.postValue(contact.getAuthor().getName());
contactAuthorId = contact.getAuthor().getId();
}
logDuration(LOG, "Loading contact", start);
@@ -310,12 +290,13 @@ public class ConversationActivity extends BriarActivity
});
}
// contactAuthorId and contactName are expected to be set
private void displayContactDetails() {
runOnUiThreadUnlessDestroyed(() -> {
//noinspection ConstantConditions
toolbarAvatar.setImageDrawable(
new IdenticonDrawable(contactAuthorId.getBytes()));
toolbarTitle.setText(contactName);
toolbarTitle.setText(contactName.getValue());
});
}
@@ -343,23 +324,9 @@ public class ConversationActivity extends BriarActivity
try {
long start = now();
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(contactId);
Collection<IntroductionMessage> introductions =
introductionManager.getIntroductionMessages(contactId);
Collection<InvitationMessage> forumInvitations =
forumSharingManager.getInvitationMessages(contactId);
Collection<InvitationMessage> blogInvitations =
blogSharingManager.getInvitationMessages(contactId);
Collection<InvitationMessage> groupInvitations =
groupInvitationManager.getInvitationMessages(contactId);
List<InvitationMessage> invitations = new ArrayList<>(
forumInvitations.size() + blogInvitations.size() +
groupInvitations.size());
invitations.addAll(forumInvitations);
invitations.addAll(blogInvitations);
invitations.addAll(groupInvitations);
conversationManager.getMessageHeaders(contactId);
logDuration(LOG, "Loading messages", start);
displayMessages(revision, headers, introductions, invitations);
displayMessages(revision, headers);
} catch (NoSuchContactException e) {
finishOnUiThread();
} catch (DbException e) {
@@ -369,15 +336,12 @@ public class ConversationActivity extends BriarActivity
}
private void displayMessages(int revision,
Collection<PrivateMessageHeader> headers,
Collection<IntroductionMessage> introductions,
Collection<InvitationMessage> invitations) {
Collection<PrivateMessageHeader> headers) {
runOnUiThreadUnlessDestroyed(() -> {
if (revision == adapter.getRevision()) {
adapter.incrementRevision();
textInputView.setSendButtonEnabled(true);
List<ConversationItem> items = createItems(headers,
introductions, invitations);
List<ConversationItem> items = createItems(headers);
adapter.addAll(items);
list.showData();
// Scroll to the bottom
@@ -396,38 +360,17 @@ public class ConversationActivity extends BriarActivity
*/
@SuppressWarnings("ConstantConditions")
private List<ConversationItem> createItems(
Collection<PrivateMessageHeader> headers,
Collection<IntroductionMessage> introductions,
Collection<InvitationMessage> invitations) {
int size =
headers.size() + introductions.size() + invitations.size();
List<ConversationItem> items = new ArrayList<>(size);
Collection<PrivateMessageHeader> headers) {
List<ConversationItem> items = new ArrayList<>(headers.size());
for (PrivateMessageHeader h : headers) {
ConversationItem item = ConversationItem.from(h);
String body = bodyCache.get(h.getId());
if (body == null) loadMessageBody(h.getId());
else item.setBody(body);
items.add(item);
}
for (IntroductionMessage m : introductions) {
ConversationItem item;
if (m instanceof IntroductionRequest) {
IntroductionRequest i = (IntroductionRequest) m;
item = ConversationItem.from(this, contactName, i);
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
item = ConversationItem.from(this, contactName.getValue(), h);
} else {
IntroductionResponse i = (IntroductionResponse) m;
item = ConversationItem.from(this, contactName, i);
}
items.add(item);
}
for (InvitationMessage i : invitations) {
ConversationItem item;
if (i instanceof InvitationRequest) {
InvitationRequest r = (InvitationRequest) i;
item = ConversationItem.from(this, contactName, r);
} else {
InvitationResponse r = (InvitationResponse) i;
item = ConversationItem.from(this, contactName, r);
item = ConversationItem.from(h);
String body = bodyCache.get(h.getId());
if (body == null) loadMessageBody(h.getId());
else item.setBody(body);
}
items.add(item);
}
@@ -476,9 +419,7 @@ public class ConversationActivity extends BriarActivity
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
if (p.getContactId().equals(contactId)) {
LOG.info("Message received, adding");
PrivateMessageHeader h = p.getMessageHeader();
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
onNewPrivateMessage(p.getMessageHeader());
}
} else if (e instanceof MessagesSentEvent) {
MessagesSentEvent m = (MessagesSentEvent) e;
@@ -504,38 +445,6 @@ public class ConversationActivity extends BriarActivity
LOG.info("Contact disconnected");
displayContactOnlineStatus();
}
} else if (e instanceof IntroductionRequestReceivedEvent) {
IntroductionRequestReceivedEvent event =
(IntroductionRequestReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Introduction request received, adding...");
IntroductionRequest ir = event.getIntroductionRequest();
handleIntroductionRequest(ir);
}
} else if (e instanceof IntroductionResponseReceivedEvent) {
IntroductionResponseReceivedEvent event =
(IntroductionResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Introduction response received, adding...");
IntroductionResponse ir = event.getIntroductionResponse();
handleIntroductionResponse(ir);
}
} else if (e instanceof InvitationRequestReceivedEvent) {
InvitationRequestReceivedEvent event =
(InvitationRequestReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation received, adding...");
InvitationRequest ir = event.getRequest();
handleInvitationRequest(ir);
}
} else if (e instanceof InvitationResponseReceivedEvent) {
InvitationResponseReceivedEvent event =
(InvitationResponseReceivedEvent) e;
if (event.getContactId().equals(contactId)) {
LOG.info("Invitation response received, adding...");
InvitationResponse ir = event.getResponse();
handleInvitationResponse(ir);
}
}
}
@@ -548,84 +457,39 @@ public class ConversationActivity extends BriarActivity
});
}
private void handleIntroductionRequest(IntroductionRequest m) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
private void onNewPrivateMessage(PrivateMessageHeader h) {
runOnUiThreadUnlessDestroyed(() -> {
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
String cName = contactName.getValue();
if (cName == null) {
// Wait for the contact name to be loaded
contactName.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String cName) {
if (cName != null) {
onNewPrivateRequestOrResponse(h, cName);
contactName.removeObserver(this);
}
}
});
} else {
onNewPrivateRequestOrResponse(h, cName);
}
} else {
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
}
});
}
private void handleIntroductionResponse(IntroductionResponse m) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
@UiThread
private void onNewPrivateRequestOrResponse(PrivateMessageHeader h,
String cName) {
addConversationItem(ConversationItem.from(this, cName, h));
}
private void handleInvitationRequest(InvitationRequest m) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
}
private void handleInvitationResponse(InvitationResponse m) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(() -> {
ConversationItem item = ConversationItem
.from(ConversationActivity.this, contactName, m);
addConversationItem(item);
});
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
}
private void markMessages(Collection<MessageId> messageIds,
boolean sent, boolean seen) {
private void markMessages(Collection<MessageId> messageIds, boolean sent,
boolean seen) {
runOnUiThreadUnlessDestroyed(() -> {
adapter.incrementRevision();
Set<MessageId> messages = new HashSet<>(messageIds);
@@ -678,7 +542,8 @@ public class ConversationActivity extends BriarActivity
//noinspection ConstantConditions init in loadGroupId()
storeMessage(privateMessageFactory.createPrivateMessage(
messagingGroupId, timestamp, body), body);
} catch (FormatException e) {throw new RuntimeException(e);
} catch (FormatException e) {
throw new RuntimeException(e);
}
});
}
@@ -823,7 +688,7 @@ public class ConversationActivity extends BriarActivity
@UiThread
@Override
public void respondToRequest(ConversationRequestItem item, boolean accept) {
item.setAnswered(true);
item.setAnswered();
int position = adapter.findItemPosition(item);
if (position != INVALID_POSITION) {
adapter.notifyItemChanged(position, item);
@@ -908,11 +773,4 @@ public class ConversationActivity extends BriarActivity
throws DbException {
groupInvitationManager.respondToInvitation(contactId, id, accept);
}
private ListenableFutureTask<String> getContactNameTask() {
if (!contactNameTaskStarted.getAndSet(true))
runOnDbThread(contactNameTask);
return contactNameTask;
}
}

View File

@@ -2,39 +2,23 @@ package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.ConversationRequestItem.RequestType;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.client.BaseMessageHeader;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.InvitationResponse;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe
@NotNullByDefault
abstract class ConversationItem {
protected @Nullable String body;
@Nullable
protected String body;
private final MessageId id;
private final GroupId groupId;
private final long time;
@@ -88,205 +72,37 @@ abstract class ConversationItem {
}
static ConversationItem from(Context ctx, String contactName,
IntroductionRequest ir) {
if (ir.isLocal()) {
String text = ctx.getString(R.string.introduction_request_sent,
contactName, ir.getName());
return new ConversationNoticeOutItem(ir.getMessageId(),
ir.getGroupId(), text, ir.getMessage(), ir.getTimestamp(),
ir.isSent(), ir.isSeen());
PrivateMessageHeader h) {
if (h.isLocal()) {
return fromLocal(ctx, contactName, h);
} else {
String text;
if (ir.wasAnswered()) {
text = ctx.getString(
R.string.introduction_request_answered_received,
contactName, ir.getName());
} else if (ir.contactExists()){
text = ctx.getString(
R.string.introduction_request_exists_received,
contactName, ir.getName());
} else {
text = ctx.getString(R.string.introduction_request_received,
contactName, ir.getName());
}
return new ConversationRequestItem(ir.getMessageId(),
ir.getGroupId(), INTRODUCTION, ir.getSessionId(), text,
ir.getMessage(), ir.getTimestamp(), ir.isRead(), null,
ir.wasAnswered(), false);
return fromRemote(ctx, contactName, h);
}
}
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());
text += "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
ir.getName());
} else {
text = ctx.getString(
R.string.introduction_response_declined_sent,
ir.getName());
}
return new ConversationNoticeOutItem(ir.getMessageId(),
ir.getGroupId(), text, null, ir.getTimestamp(), ir.isSent(),
ir.isSeen());
private static ConversationItem fromLocal(Context ctx, String contactName,
PrivateMessageHeader h) {
if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h;
return new ConversationNoticeOutItem(ctx, contactName, r);
} else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h;
return new ConversationNoticeOutItem(ctx, contactName, r);
} 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(),
ir.getGroupId(), text, null, ir.getTimestamp(),
ir.isRead());
return new ConversationMessageOutItem(h);
}
}
static ConversationItem from(Context ctx, String contactName,
InvitationRequest ir) {
if (ir.isLocal()) {
String text;
if (ir instanceof ForumInvitationRequest) {
text = ctx.getString(R.string.forum_invitation_sent,
((ForumInvitationRequest) ir).getForumName(),
contactName);
} else if (ir instanceof BlogInvitationRequest) {
text = ctx.getString(R.string.blogs_sharing_invitation_sent,
((BlogInvitationRequest) ir).getBlogAuthorName(),
contactName);
} else if (ir instanceof GroupInvitationRequest) {
text = ctx.getString(
R.string.groups_invitations_invitation_sent,
contactName, ir.getShareable().getName());
} else {
throw new IllegalArgumentException("Unknown InvitationRequest");
}
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
text, ir.getMessage(), ir.getTimestamp(), ir.isSent(),
ir.isSeen());
private static ConversationItem fromRemote(Context ctx, String contactName,
PrivateMessageHeader h) {
if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h;
return new ConversationRequestItem(ctx, contactName, r);
} else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h;
return new ConversationNoticeInItem(ctx, contactName, r);
} else {
String text;
RequestType type;
if (ir instanceof ForumInvitationRequest) {
text = ctx.getString(R.string.forum_invitation_received,
contactName,
((ForumInvitationRequest) ir).getForumName());
type = FORUM;
} else if (ir instanceof BlogInvitationRequest) {
text = ctx.getString(R.string.blogs_sharing_invitation_received,
contactName,
((BlogInvitationRequest) ir).getBlogAuthorName());
type = BLOG;
} else if (ir instanceof GroupInvitationRequest) {
text = ctx.getString(
R.string.groups_invitations_invitation_received,
contactName, ir.getShareable().getName());
type = GROUP;
} else {
throw new IllegalArgumentException("Unknown InvitationRequest");
}
return new ConversationRequestItem(ir.getId(),
ir.getGroupId(), type, ir.getSessionId(), text,
ir.getMessage(), ir.getTimestamp(), ir.isRead(),
ir.getShareable().getId(), !ir.isAvailable(),
ir.canBeOpened());
}
}
static ConversationItem from(Context ctx, String contactName,
InvitationResponse ir) {
@StringRes int res;
if (ir.isLocal()) {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_sent;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_accepted_sent;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_accepted_sent;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
} else {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_declined_sent;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_declined_sent;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_declined_sent;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
}
String text = ctx.getString(res, contactName);
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
text, null, ir.getTimestamp(), ir.isSent(), ir.isSeen());
} else {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_received;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_accepted_received;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_accepted_received;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
} else {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_declined_received;
} else if (ir instanceof BlogInvitationResponse) {
res = R.string.blogs_sharing_response_declined_received;
} else if (ir instanceof GroupInvitationResponse) {
res = R.string.groups_invitations_response_declined_received;
} else {
throw new IllegalArgumentException(
"Unknown InvitationResponse");
}
}
String text = ctx.getString(res, contactName);
return new ConversationNoticeInItem(ir.getId(), ir.getGroupId(),
text, null, ir.getTimestamp(), ir.isRead());
}
}
/**
* This method should not be used to display the resulting ConversationItem
* in the UI, but only to update list information based on the
* BaseMessageHeader.
**/
static ConversationItem from(Context ctx, BaseMessageHeader h) {
if (h instanceof PrivateMessageHeader) {
return from((PrivateMessageHeader) h);
} else if(h instanceof IntroductionRequest) {
return from(ctx, "", (IntroductionRequest) h);
} else if(h instanceof IntroductionResponse) {
return from(ctx, "", (IntroductionResponse) h);
} else if(h instanceof InvitationRequest) {
return from(ctx, "", (InvitationRequest) h);
} else if(h instanceof InvitationResponse) {
return from(ctx, "", (InvitationResponse) h);
} else {
throw new IllegalArgumentException("Unknown message header");
return new ConversationMessageInItem(h);
}
}

View File

@@ -1,11 +1,18 @@
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@@ -24,6 +31,13 @@ class ConversationNoticeInItem extends ConversationItem {
this.msgText = msgText;
}
public ConversationNoticeInItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isRead());
this.msgText = null;
}
@Nullable
String getMsgText() {
return msgText;
@@ -40,4 +54,54 @@ class ConversationNoticeInItem extends ConversationItem {
return R.layout.list_item_conversation_notice_in;
}
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
return ctx.getString(
R.string.introduction_response_accepted_received,
contactName, ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_accepted_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_accepted_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_accepted_received,
contactName);
}
} else {
if (r instanceof IntroductionResponse) {
IntroductionResponse ir = (IntroductionResponse) r;
@StringRes int res;
if (ir.isIntroducer()) {
res = R.string.introduction_response_declined_received;
} else {
res =
R.string.introduction_response_declined_received_by_introducee;
}
return ctx.getString(res, contactName,
ir.getIntroducedAuthor().getName());
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(
R.string.forum_invitation_response_declined_received,
contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(
R.string.blogs_sharing_response_declined_received,
contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(
R.string.groups_invitations_response_declined_received,
contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
}

View File

@@ -1,11 +1,20 @@
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.blog.BlogInvitationResponse;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.forum.ForumInvitationResponse;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.introduction.IntroductionResponse;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
@@ -17,11 +26,18 @@ class ConversationNoticeOutItem extends ConversationOutItem {
@Nullable
private final String msgText;
ConversationNoticeOutItem(MessageId id, GroupId groupId,
String text, @Nullable String msgText, long time,
boolean sent, boolean seen) {
super(id, groupId, text, time, sent, seen);
this.msgText = msgText;
ConversationNoticeOutItem(Context ctx, String contactName,
PrivateRequest r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isSent(), r.isSeen());
this.msgText = r.getMessage();
}
ConversationNoticeOutItem(Context ctx, String contactName,
PrivateResponse r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getTimestamp(), r.isSent(), r.isSeen());
this.msgText = null;
}
@Nullable
@@ -35,4 +51,57 @@ class ConversationNoticeOutItem extends ConversationOutItem {
return R.layout.list_item_conversation_notice_out;
}
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return ctx.getString(R.string.introduction_request_sent,
contactName, r.getName());
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_sent,
r.getName(), contactName);
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_sent,
r.getName(), contactName);
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(R.string.groups_invitations_invitation_sent,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static String getText(Context ctx, String contactName,
PrivateResponse r) {
if (r.wasAccepted()) {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_accepted_sent,
name) + "\n\n" + ctx.getString(
R.string.introduction_response_accepted_sent_info,
name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_accepted_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_accepted_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_accepted_sent, contactName);
}
} else {
if (r instanceof IntroductionResponse) {
String name = ((IntroductionResponse) r).getIntroducedAuthor()
.getName();
return ctx.getString(
R.string.introduction_response_declined_sent, name);
} else if (r instanceof ForumInvitationResponse) {
return ctx.getString(R.string.forum_invitation_response_declined_sent, contactName);
} else if (r instanceof BlogInvitationResponse) {
return ctx.getString(R.string.blogs_sharing_response_declined_sent, contactName);
} else if (r instanceof GroupInvitationResponse) {
return ctx.getString(R.string.groups_invitations_response_declined_sent, contactName);
}
}
throw new IllegalArgumentException("Unknown PrivateResponse");
}
}

View File

@@ -1,16 +1,28 @@
package org.briarproject.briar.android.contact;
import android.content.Context;
import android.support.annotation.LayoutRes;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.api.blog.BlogInvitationRequest;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.forum.ForumInvitationRequest;
import org.briarproject.briar.api.introduction.IntroductionRequest;
import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
import org.briarproject.briar.api.sharing.InvitationRequest;
import org.briarproject.briar.api.sharing.Shareable;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe
@NotNullByDefault
class ConversationRequestItem extends ConversationNoticeInItem {
@@ -24,17 +36,20 @@ class ConversationRequestItem extends ConversationNoticeInItem {
private final boolean canBeOpened;
private boolean answered;
ConversationRequestItem(MessageId id, GroupId groupId,
RequestType requestType, SessionId sessionId, String text,
@Nullable String msgText, long time, boolean read,
@Nullable GroupId requestedGroupId, boolean answered,
boolean canBeOpened) {
super(id, groupId, text, msgText, time, read);
this.requestType = requestType;
this.sessionId = sessionId;
this.requestedGroupId = requestedGroupId;
this.answered = answered;
this.canBeOpened = canBeOpened;
ConversationRequestItem(Context ctx, String contactName,
PrivateRequest r) {
super(r.getId(), r.getGroupId(), getText(ctx, contactName, r),
r.getMessage(), r.getTimestamp(), r.isRead());
this.requestType = getType(r);
this.sessionId = r.getSessionId();
this.answered = r.wasAnswered();
if (r instanceof InvitationRequest) {
this.requestedGroupId = ((Shareable) r.getNameable()).getId();
this.canBeOpened = ((InvitationRequest) r).canBeOpened();
} else {
this.requestedGroupId = null;
this.canBeOpened = false;
}
}
RequestType getRequestType() {
@@ -54,8 +69,8 @@ class ConversationRequestItem extends ConversationNoticeInItem {
return answered;
}
void setAnswered(boolean answered) {
this.answered = answered;
void setAnswered() {
this.answered = true;
}
public boolean canBeOpened() {
@@ -68,4 +83,46 @@ class ConversationRequestItem extends ConversationNoticeInItem {
return R.layout.list_item_conversation_request;
}
private static String getText(Context ctx, String contactName,
PrivateRequest r) {
if (r instanceof IntroductionRequest) {
if (r.wasAnswered()) {
return ctx.getString(
R.string.introduction_request_answered_received,
contactName, r.getName());
} else if (((IntroductionRequest) r).isContact()) {
return ctx.getString(
R.string.introduction_request_exists_received,
contactName, r.getName());
} else {
return ctx.getString(R.string.introduction_request_received,
contactName, r.getName());
}
} else if (r instanceof ForumInvitationRequest) {
return ctx.getString(R.string.forum_invitation_received,
contactName, r.getName());
} else if (r instanceof BlogInvitationRequest) {
return ctx.getString(R.string.blogs_sharing_invitation_received,
contactName, r.getName());
} else if (r instanceof GroupInvitationRequest) {
return ctx.getString(
R.string.groups_invitations_invitation_received,
contactName, r.getName());
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
private static RequestType getType(PrivateRequest r) {
if (r instanceof IntroductionRequest) {
return INTRODUCTION;
} else if (r instanceof ForumInvitationRequest) {
return FORUM;
} else if (r instanceof BlogInvitationRequest) {
return BLOG;
} else if (r instanceof GroupInvitationRequest) {
return GROUP;
}
throw new IllegalArgumentException("Unknown PrivateRequest");
}
}

View File

@@ -84,11 +84,10 @@ class ForumControllerImpl extends
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent f =
(ForumInvitationResponseReceivedEvent) e;
ForumInvitationResponse r =
(ForumInvitationResponse) f.getResponse();
ForumInvitationResponse r = f.getMessageHeader();
if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) {
LOG.info("Forum invitation was accepted");
onForumInvitationAccepted(r.getContactId());
onForumInvitationAccepted(f.getContactId());
}
} else if (e instanceof ContactLeftShareableEvent) {
ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;

View File

@@ -99,11 +99,10 @@ class GroupControllerImpl extends
} else if (e instanceof GroupInvitationResponseReceivedEvent) {
GroupInvitationResponseReceivedEvent g =
(GroupInvitationResponseReceivedEvent) e;
GroupInvitationResponse r =
(GroupInvitationResponse) g.getResponse();
GroupInvitationResponse r = g.getMessageHeader();
if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) {
listener.runOnUiThreadUnlessDestroyed(
() -> listener.onInvitationAccepted(r.getContactId()));
() -> listener.onInvitationAccepted(g.getContactId()));
}
} else if (e instanceof GroupDissolvedEvent) {
GroupDissolvedEvent g = (GroupDissolvedEvent) e;

View File

@@ -1,23 +0,0 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
public interface FutureTaskListener<V> {
void onSuccess(V result);
void onFailure(Throwable error);
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javax.annotation.Nullable;
public class ListenableFutureTask<V> extends FutureTask<V> {
private final List<FutureTaskListener<V>> listeners = new LinkedList<>();
@Nullable
private final Object identifier;
public ListenableFutureTask(Callable<V> callable) {
this(callable, null);
}
private ListenableFutureTask(Callable<V> callable,
@Nullable Object identifier) {
super(callable);
this.identifier = identifier;
}
public ListenableFutureTask(V result) {
this(result, null);
}
private ListenableFutureTask(V result, @Nullable Object identifier) {
super(() -> result);
this.identifier = identifier;
this.run();
}
public synchronized void addListener(FutureTaskListener<V> listener) {
if (this.isDone()) {
callback(listener);
} else {
this.listeners.add(listener);
}
}
public synchronized void removeListener(FutureTaskListener<V> listener) {
this.listeners.remove(listener);
}
@Override
protected synchronized void done() {
callback();
}
private void callback() {
for (FutureTaskListener<V> listener : listeners) {
callback(listener);
}
}
private void callback(FutureTaskListener<V> listener) {
if (listener != null) {
try {
listener.onSuccess(get());
} catch (InterruptedException e) {
throw new AssertionError(e);
} catch (ExecutionException e) {
listener.onFailure(e);
}
}
}
@Override
public boolean equals(Object other) {
if (other != null && other instanceof ListenableFutureTask &&
this.identifier != null) {
return identifier.equals(other);
} else {
return super.equals(other);
}
}
@Override
public int hashCode() {
if (identifier != null) return identifier.hashCode();
else return super.hashCode();
}
}