diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index bd35788a2..c82dab5ef 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -169,12 +169,18 @@
Group Invitations
+ You have invited %1$s to your group "%2$s".
+ %1$s has invited you to join the group "%2$s".
Joined Group
Group Invitation Declined
- %d open group invitation
- %d open group invitations
+ You accepted the group invitation from %s.
+ You declined the group invitation from %s.
+ %s accepted your group invitation.
+ %s declined your group invitation.
You don\'t have any forums yet.\n\nWhy don\'t you create a new one yourself by tapping the + icon at the top?\n\nYou can also ask your contacts to share forums with you.
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index deb794403..a5c7aef1d 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -286,8 +286,9 @@ public class ContactListFragment extends BaseFragment implements EventListener {
updateItem(m.getContactId(),
ConversationItem.from(getContext(), "", ir));
} else if (e instanceof InvitationRequestReceivedEvent) {
- LOG.info("Invitation request received, updating item");
- InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
+ LOG.info("Invitation Request received, update item");
+ InvitationRequestReceivedEvent m =
+ (InvitationRequestReceivedEvent) e;
InvitationRequest ir = m.getRequest();
updateItem(m.getContactId(),
ConversationItem.from(getContext(), "", ir));
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 5eac456b6..ea618642f 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -67,6 +67,7 @@ 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.privategroup.invitation.GroupInvitationManager;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager;
import org.briarproject.api.sharing.InvitationMessage;
@@ -146,6 +147,8 @@ public class ConversationActivity extends BriarActivity
volatile ForumSharingManager forumSharingManager;
@Inject
volatile BlogSharingManager blogSharingManager;
+ @Inject
+ volatile GroupInvitationManager groupInvitationManager;
private volatile GroupId groupId = null;
private volatile ContactId contactId = null;
@@ -351,10 +354,14 @@ public class ConversationActivity extends BriarActivity
Collection blogInvitations =
blogSharingManager
.getInvitationMessages(contactId);
+ Collection groupInvitations =
+ groupInvitationManager
+ .getInvitationMessages(contactId);
List invitations = new ArrayList<>(
forumInvitations.size() + blogInvitations.size());
invitations.addAll(forumInvitations);
invitations.addAll(blogInvitations);
+ invitations.addAll(groupInvitations);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Loading messages took " + duration + " ms");
@@ -398,44 +405,46 @@ public class ConversationActivity extends BriarActivity
Collection headers,
Collection introductions,
Collection invitations) {
- int size = headers.size() + introductions.size() + invitations.size();
+ int size =
+ headers.size() + introductions.size() + invitations.size();
List items = new ArrayList<>(size);
-
- for (PrivateMessageHeader h : headers) {
- ConversationItem item = ConversationItem.from(h);
- String body = bodyCache.get(h.getId());
- if (body == null) loadMessageBody(h.getId());
- else ((PartialItem) item).setText(body);
- items.add(item);
+ for (PrivateMessageHeader h : headers) {
+ ConversationItem item = ConversationItem.from(h);
+ String body = bodyCache.get(h.getId());
+ if (body == null) loadMessageBody(h.getId());
+ else ((PartialItem) item).setText(body);
+ items.add(item);
+ }
+ for (IntroductionMessage m : introductions) {
+ ConversationItem item;
+ if (m instanceof IntroductionRequest) {
+ item = ConversationItem
+ .from(ConversationActivity.this,
+ contactName,
+ (IntroductionRequest) m);
+ } else {
+ item = ConversationItem
+ .from(ConversationActivity.this,
+ contactName,
+ (IntroductionResponse) m);
}
- for (IntroductionMessage m : introductions) {
- ConversationItem item;
- if (m instanceof IntroductionRequest) {
- item = ConversationItem
- .from(ConversationActivity.this,
- contactName,
- (IntroductionRequest) m);
- } else {
- item = ConversationItem
- .from(ConversationActivity.this,
- contactName,
- (IntroductionResponse) m);
- }
- items.add(item);
- }
- for (InvitationMessage i : invitations) {
- if (i instanceof InvitationRequest) {
- InvitationRequest r = (InvitationRequest) i;
- items.add(ConversationItem
- .from(ConversationActivity.this,
- contactName, r));
- } else if (i instanceof InvitationResponse) {
- InvitationResponse r = (InvitationResponse) i;
- items.add(ConversationItem
- .from(ConversationActivity.this,
- contactName, r));
- }
+ items.add(item);
+ }
+ for (InvitationMessage i : invitations) {
+ ConversationItem item;
+ if (i instanceof InvitationRequest) {
+ InvitationRequest r = (InvitationRequest) i;
+ item = ConversationItem
+ .from(ConversationActivity.this,
+ contactName, r);
+ } else {
+ InvitationResponse r = (InvitationResponse) i;
+ item = ConversationItem
+ .from(ConversationActivity.this,
+ contactName, r);
}
+ items.add(item);
+ }
return items;
}
@@ -850,6 +859,9 @@ public class ConversationActivity extends BriarActivity
case BLOG:
respondToBlogRequest(item.getSessionId(), accept);
break;
+ case GROUP:
+ respondToGroupRequest(item.getSessionId(), accept);
+ break;
default:
throw new IllegalArgumentException(
"Unknown Request Type");
@@ -889,6 +901,13 @@ public class ConversationActivity extends BriarActivity
loadMessages();
}
+ @DatabaseExecutor
+ private void respondToGroupRequest(SessionId id, boolean accept)
+ throws DbException {
+ groupInvitationManager.respondToInvitation(id, accept);
+ loadMessages();
+ }
+
private void introductionResponseError() {
runOnUiThreadUnlessDestroyed(new Runnable() {
@Override
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationItem.java b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
index 9d1749ae8..e687935f2 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
@@ -6,12 +6,15 @@ import android.support.annotation.StringRes;
import org.briarproject.R;
import org.briarproject.android.contact.ConversationRequestItem.RequestType;
import org.briarproject.api.blogs.BlogInvitationRequest;
+import org.briarproject.api.blogs.BlogInvitationResponse;
import org.briarproject.api.forum.ForumInvitationRequest;
import org.briarproject.api.forum.ForumInvitationResponse;
import org.briarproject.api.introduction.IntroductionRequest;
import org.briarproject.api.introduction.IntroductionResponse;
import org.briarproject.api.messaging.PrivateMessageHeader;
import org.briarproject.api.nullsafety.NotNullByDefault;
+import org.briarproject.api.privategroup.invitation.GroupInvitationRequest;
+import org.briarproject.api.privategroup.invitation.GroupInvitationResponse;
import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sharing.InvitationResponse;
import org.briarproject.api.sync.GroupId;
@@ -22,6 +25,7 @@ import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.android.contact.ConversationRequestItem.RequestType.BLOG;
import static org.briarproject.android.contact.ConversationRequestItem.RequestType.FORUM;
+import static org.briarproject.android.contact.ConversationRequestItem.RequestType.GROUP;
import static org.briarproject.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
@NotThreadSafe
@@ -145,10 +149,17 @@ abstract class ConversationItem {
text = ctx.getString(R.string.forum_invitation_sent,
((ForumInvitationRequest) ir).getForumName(),
contactName);
- } else {
+ } 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,
+ ((GroupInvitationRequest) ir).getGroupName());
+ } else {
+ throw new IllegalArgumentException("Unknown InvitationRequest");
}
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
text, ir.getMessage(), ir.getTimestamp(), ir.isSent(),
@@ -161,11 +172,19 @@ abstract class ConversationItem {
contactName,
((ForumInvitationRequest) ir).getForumName());
type = FORUM;
- } else {
+ } 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,
+ ((GroupInvitationRequest) ir).getGroupName());
+ type = GROUP;
+ } else {
+ throw new IllegalArgumentException("Unknown InvitationRequest");
}
if (!ir.isAvailable()) {
return new ConversationNoticeInItem(ir.getId(), ir.getGroupId(),
@@ -185,14 +204,24 @@ abstract class ConversationItem {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_sent;
- } else {
+ } 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 {
+ } 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);
@@ -202,14 +231,24 @@ abstract class ConversationItem {
if (ir.wasAccepted()) {
if (ir instanceof ForumInvitationResponse) {
res = R.string.forum_invitation_response_accepted_received;
- } else {
+ } 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 {
+ } 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);
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationRequestItem.java b/briar-android/src/org/briarproject/android/contact/ConversationRequestItem.java
index 9999350d4..2b8521f7f 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationRequestItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationRequestItem.java
@@ -12,7 +12,7 @@ import javax.annotation.concurrent.NotThreadSafe;
@NotNullByDefault
class ConversationRequestItem extends ConversationNoticeInItem {
- enum RequestType { INTRODUCTION, FORUM, BLOG };
+ enum RequestType { INTRODUCTION, FORUM, BLOG, GROUP };
private final RequestType requestType;
private final SessionId sessionId;
private boolean answered;
diff --git a/briar-api/src/org/briarproject/api/clients/BaseMessage.java b/briar-api/src/org/briarproject/api/clients/BaseMessage.java
index 776bfcf5c..fbfb56337 100644
--- a/briar-api/src/org/briarproject/api/clients/BaseMessage.java
+++ b/briar-api/src/org/briarproject/api/clients/BaseMessage.java
@@ -1,21 +1,26 @@
package org.briarproject.api.clients;
+import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+@NotNullByDefault
public abstract class BaseMessage {
private final Message message;
+ @Nullable
private final MessageId parent;
- public BaseMessage(@NotNull Message message, @Nullable MessageId parent) {
+ public BaseMessage(Message message, @Nullable MessageId parent) {
this.message = message;
this.parent = parent;
}
- @NotNull
public Message getMessage() {
return message;
}
diff --git a/briar-api/src/org/briarproject/api/privategroup/GroupMessage.java b/briar-api/src/org/briarproject/api/privategroup/GroupMessage.java
index 22457de2e..06f277460 100644
--- a/briar-api/src/org/briarproject/api/privategroup/GroupMessage.java
+++ b/briar-api/src/org/briarproject/api/privategroup/GroupMessage.java
@@ -2,17 +2,22 @@ package org.briarproject.api.privategroup;
import org.briarproject.api.clients.BaseMessage;
import org.briarproject.api.identity.Author;
+import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+@NotNullByDefault
public class GroupMessage extends BaseMessage {
private final Author author;
- public GroupMessage(@NotNull Message message, @Nullable MessageId parent,
- @NotNull Author author) {
+ public GroupMessage(Message message, @Nullable MessageId parent,
+ Author author) {
super(message, parent);
this.author = author;
}
diff --git a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationItem.java b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationItem.java
index c7f350be4..16688b37c 100644
--- a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationItem.java
+++ b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationItem.java
@@ -1,9 +1,14 @@
package org.briarproject.api.privategroup.invitation;
import org.briarproject.api.contact.Contact;
+import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sharing.InvitationItem;
import org.briarproject.api.sharing.Shareable;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+@NotNullByDefault
public class GroupInvitationItem extends InvitationItem {
private final Contact creator;
diff --git a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationRequest.java b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationRequest.java
index 3c9b25760..3115a6bc2 100644
--- a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationRequest.java
+++ b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationRequest.java
@@ -8,9 +8,10 @@ import org.briarproject.api.sharing.InvitationRequest;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
+import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
-@ThreadSafe
+@Immutable
@NotNullByDefault
public class GroupInvitationRequest extends InvitationRequest {
diff --git a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationResponse.java b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationResponse.java
index 554e731bc..dda5d554a 100644
--- a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationResponse.java
+++ b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationResponse.java
@@ -9,9 +9,10 @@ import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jetbrains.annotations.NotNull;
+import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
-@ThreadSafe
+@Immutable
@NotNullByDefault
public class GroupInvitationResponse extends InvitationResponse {
diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationItem.java b/briar-api/src/org/briarproject/api/sharing/InvitationItem.java
index a813982b1..423edf3b3 100644
--- a/briar-api/src/org/briarproject/api/sharing/InvitationItem.java
+++ b/briar-api/src/org/briarproject/api/sharing/InvitationItem.java
@@ -3,9 +3,10 @@ package org.briarproject.api.sharing;
import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.GroupId;
+import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
-@ThreadSafe
+@Immutable
@NotNullByDefault
public abstract class InvitationItem {
diff --git a/briar-api/src/org/briarproject/api/sharing/SharingInvitationItem.java b/briar-api/src/org/briarproject/api/sharing/SharingInvitationItem.java
index 8993f2320..ddbc3cba4 100644
--- a/briar-api/src/org/briarproject/api/sharing/SharingInvitationItem.java
+++ b/briar-api/src/org/briarproject/api/sharing/SharingInvitationItem.java
@@ -1,9 +1,14 @@
package org.briarproject.api.sharing;
import org.briarproject.api.contact.Contact;
+import org.briarproject.api.nullsafety.NotNullByDefault;
import java.util.Collection;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+@NotNullByDefault
public class SharingInvitationItem extends InvitationItem {
private final Collection newSharers;