diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 99ad3cfad..774f1c7f9 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -142,6 +142,17 @@
/>
+
+
+
+
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 6acd446ff..73046ee63 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -157,6 +157,7 @@
Create Group
Send Invitation
Add a name for your private group
+ Group invitation has been sent
Compose Message
Message sent
Message received
diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java
index d2902428d..ee1ee02d5 100644
--- a/briar-android/src/org/briarproject/android/ActivityComponent.java
+++ b/briar-android/src/org/briarproject/android/ActivityComponent.java
@@ -32,6 +32,7 @@ import org.briarproject.android.privategroup.conversation.GroupActivity;
import org.briarproject.android.privategroup.creation.CreateGroupActivity;
import org.briarproject.android.privategroup.creation.CreateGroupFragment;
import org.briarproject.android.privategroup.creation.CreateGroupMessageFragment;
+import org.briarproject.android.privategroup.creation.GroupInviteActivity;
import org.briarproject.android.privategroup.invitation.GroupInvitationActivity;
import org.briarproject.android.privategroup.list.GroupListFragment;
import org.briarproject.android.privategroup.memberlist.GroupMemberListActivity;
@@ -80,6 +81,7 @@ public interface ActivityComponent {
void inject(CreateGroupActivity activity);
void inject(GroupActivity activity);
+ void inject(GroupInviteActivity activity);
void inject(GroupInvitationActivity activity);
void inject(GroupMemberListActivity activity);
diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java
index a6a806604..1dad3b51a 100644
--- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java
+++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java
@@ -19,6 +19,7 @@ import org.briarproject.R;
import org.briarproject.android.ActivityComponent;
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
import org.briarproject.android.privategroup.memberlist.GroupMemberListActivity;
+import org.briarproject.android.privategroup.creation.GroupInviteActivity;
import org.briarproject.android.threaded.ThreadListActivity;
import org.briarproject.android.threaded.ThreadListController;
import org.briarproject.api.db.DbException;
@@ -34,6 +35,8 @@ public class GroupActivity extends
ThreadListActivity
implements OnClickListener {
+ private final static int REQUEST_INVITE = 1;
+
@Inject
GroupController controller;
@@ -133,17 +136,23 @@ public class GroupActivity extends
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
+ ActivityOptionsCompat options =
+ makeCustomAnimation(this, android.R.anim.slide_in_left,
+ android.R.anim.slide_out_right);
switch (item.getItemId()) {
case R.id.action_group_compose_message:
showTextInput(null);
return true;
case R.id.action_group_member_list:
- Intent i = new Intent(this, GroupMemberListActivity.class);
- i.putExtra(GROUP_ID, groupId.getBytes());
- ActivityOptionsCompat options =
- makeCustomAnimation(this, android.R.anim.slide_in_left,
- android.R.anim.slide_out_right);
- ActivityCompat.startActivity(this, i, options.toBundle());
+ Intent i1 = new Intent(this, GroupMemberListActivity.class);
+ i1.putExtra(GROUP_ID, groupId.getBytes());
+ ActivityCompat.startActivity(this, i1, options.toBundle());
+ return true;
+ case R.id.action_group_invite:
+ Intent i2 = new Intent(this, GroupInviteActivity.class);
+ i2.putExtra(GROUP_ID, groupId.getBytes());
+ ActivityCompat.startActivityForResult(this, i2, REQUEST_INVITE,
+ options.toBundle());
return true;
case R.id.action_group_leave:
showLeaveGroupDialog();
@@ -155,6 +164,13 @@ public class GroupActivity extends
}
}
+ @Override
+ protected void onActivityResult(int request, int result, Intent data) {
+ if (request == REQUEST_INVITE && result == RESULT_OK) {
+ displaySnackbarShort(R.string.groups_invitation_sent);
+ } else super.onActivityResult(request, result, data);
+ }
+
@Override
protected int getMaxBodyLength() {
return MAX_GROUP_POST_BODY_LENGTH;
diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java
new file mode 100644
index 000000000..1d29ce89d
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/privategroup/creation/BaseGroupInviteActivity.java
@@ -0,0 +1,95 @@
+package org.briarproject.android.privategroup.creation;
+
+import android.os.Bundle;
+import android.widget.Toast;
+
+import org.briarproject.R;
+import org.briarproject.android.controller.handler.UiResultExceptionHandler;
+import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener;
+import org.briarproject.android.sharing.ContactSelectorActivity;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DatabaseExecutor;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.sync.GroupId;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import static android.widget.Toast.LENGTH_SHORT;
+import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
+
+public abstract class BaseGroupInviteActivity
+ extends ContactSelectorActivity
+ implements MessageFragmentListener {
+
+ @Inject
+ CreateGroupController controller;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ // Subclasses may initialise the group ID in different places,
+ // restore it if it was saved
+ if (bundle != null) {
+ byte[] groupBytes = bundle.getByteArray(GROUP_ID);
+ if (groupBytes != null) groupId = new GroupId(groupBytes);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (groupId != null) {
+ outState.putByteArray(GROUP_ID, groupId.getBytes());
+ }
+ }
+
+ @Override
+ public void contactsSelected(GroupId groupId,
+ Collection contacts) {
+ super.contactsSelected(groupId, contacts);
+
+ CreateGroupMessageFragment fragment = new CreateGroupMessageFragment();
+ getSupportFragmentManager().beginTransaction()
+ .setCustomAnimations(android.R.anim.fade_in,
+ android.R.anim.fade_out,
+ android.R.anim.slide_in_left,
+ android.R.anim.slide_out_right)
+ .replace(R.id.fragmentContainer, fragment)
+ .addToBackStack(fragment.getUniqueTag())
+ .commit();
+ }
+
+ @Override
+ public boolean onButtonClick(@NotNull String message) {
+ controller.sendInvitation(groupId, contacts, message,
+ new UiResultExceptionHandler(this) {
+ @Override
+ public void onResultUi(Void result) {
+ Toast.makeText(BaseGroupInviteActivity.this,
+ "Inviting members is not yet implemented",
+ LENGTH_SHORT).show();
+ setResult(RESULT_OK);
+ supportFinishAfterTransition();
+ }
+
+ @Override
+ public void onExceptionUi(DbException exception) {
+ // TODO proper error handling
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ return true;
+ }
+
+ @Override
+ public int getMaximumMessageLength() {
+ return MAX_GROUP_INVITATION_MSG_LENGTH;
+ }
+
+}
diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java
index d92759820..a82b4cc1d 100644
--- a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java
+++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java
@@ -4,35 +4,23 @@ import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
-import android.widget.Toast;
import org.briarproject.R;
import org.briarproject.android.ActivityComponent;
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
import org.briarproject.android.privategroup.conversation.GroupActivity;
import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener;
-import org.briarproject.android.sharing.ContactSelectorActivity;
import org.briarproject.android.sharing.ContactSelectorFragment;
import org.briarproject.api.contact.Contact;
-import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException;
import org.briarproject.api.sync.GroupId;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-
-import javax.inject.Inject;
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
-import static android.widget.Toast.LENGTH_SHORT;
-import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
-public class CreateGroupActivity extends ContactSelectorActivity implements
+public class CreateGroupActivity extends BaseGroupInviteActivity implements
CreateGroupListener, MessageFragmentListener {
- @Inject
- CreateGroupController controller;
-
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
@@ -42,19 +30,21 @@ public class CreateGroupActivity extends ContactSelectorActivity implements
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
- setContentView(R.layout.activity_fragment_container);
-
if (bundle == null) {
CreateGroupFragment fragment = new CreateGroupFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
- } else {
- byte[] groupBytes = bundle.getByteArray(GROUP_ID);
- if (groupBytes != null) groupId = new GroupId(groupBytes);
}
}
+ @Override
+ @DatabaseExecutor
+ public boolean isDisabled(GroupId groupId, Contact c) throws DbException {
+ // contacts can always be invited into a new group
+ return false;
+ }
+
@Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
@@ -66,14 +56,6 @@ public class CreateGroupActivity extends ContactSelectorActivity implements
}
}
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (groupId != null) {
- outState.putByteArray(GROUP_ID, groupId.getBytes());
- }
- }
-
@Override
public void onGroupNameChosen(String name) {
controller.createGroup(name,
@@ -106,53 +88,6 @@ public class CreateGroupActivity extends ContactSelectorActivity implements
.commit();
}
- @Override
- public boolean isDisabled(GroupId groupId, Contact c) throws DbException {
- return false;
- }
-
- @Override
- public void contactsSelected(GroupId groupId,
- Collection contacts) {
- super.contactsSelected(groupId, contacts);
-
- CreateGroupMessageFragment fragment = new CreateGroupMessageFragment();
- getSupportFragmentManager().beginTransaction()
- .setCustomAnimations(android.R.anim.fade_in,
- android.R.anim.fade_out,
- android.R.anim.slide_in_left,
- android.R.anim.slide_out_right)
- .replace(R.id.fragmentContainer, fragment)
- .addToBackStack(fragment.getUniqueTag())
- .commit();
- }
-
- @Override
- public boolean onButtonClick(@NotNull String message) {
- controller.sendInvitation(groupId, contacts, message,
- new UiResultExceptionHandler(this) {
- @Override
- public void onResultUi(Void result) {
- Toast.makeText(CreateGroupActivity.this,
- "Inviting members is not yet implemented",
- LENGTH_SHORT).show();
- openNewGroup();
- }
-
- @Override
- public void onExceptionUi(DbException exception) {
- // TODO proper error handling
- finish();
- }
- });
- return true;
- }
-
- @Override
- public int getMaximumMessageLength() {
- return MAX_GROUP_INVITATION_MSG_LENGTH;
- }
-
private void openNewGroup() {
Intent i = new Intent(this, GroupActivity.class);
i.putExtra(GROUP_ID, groupId.getBytes());
diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/GroupInviteActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/GroupInviteActivity.java
new file mode 100644
index 000000000..7872c34cb
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/privategroup/creation/GroupInviteActivity.java
@@ -0,0 +1,50 @@
+package org.briarproject.android.privategroup.creation;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener;
+import org.briarproject.android.sharing.ContactSelectorFragment;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.db.DatabaseExecutor;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.sync.GroupId;
+
+public class GroupInviteActivity extends BaseGroupInviteActivity
+ implements MessageFragmentListener {
+
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ // Initialise the group ID,
+ // it will be saved and restored by the superclass
+ Intent i = getIntent();
+ byte[] g = i.getByteArrayExtra(GROUP_ID);
+ if (g == null) throw new IllegalStateException("No GroupId in intent.");
+ groupId = new GroupId(g);
+
+ if (bundle == null) {
+ ContactSelectorFragment fragment =
+ ContactSelectorFragment.newInstance(groupId);
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragmentContainer, fragment)
+ .commit();
+ }
+ }
+
+ @Override
+ @DatabaseExecutor
+ public boolean isDisabled(GroupId groupId, Contact c) throws DbException {
+ // TODO disable contacts that can not be invited
+ return false;
+ }
+
+}