diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 99ad3cfada95848bac44c53f9f195fdc71032623..774f1c7f966d7bdb6bb90307e4e8f17e1fa452ca 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -142,6 +142,17 @@ /> </activity> + <activity + android:name=".android.privategroup.creation.GroupInviteActivity" + android:label="@string/groups_invite_members" + android:parentActivityName=".android.NavDrawerActivity" + android:windowSoftInputMode="adjustResize|stateHidden"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.privategroup.conversation.GroupActivity" + /> + </activity> + <activity android:name=".android.sharing.ForumInvitationActivity" android:label="@string/forum_invitations_title" diff --git a/briar-android/res/menu/group_actions.xml b/briar-android/res/menu/group_actions.xml index d7901bdfa01f01fa4a172bbfe71af68006350664..0c1fd68fa75fb566dca4e7126b9137e16443c298 100644 --- a/briar-android/res/menu/group_actions.xml +++ b/briar-android/res/menu/group_actions.xml @@ -17,7 +17,6 @@ <item android:id="@+id/action_group_invite" - android:enabled="false" android:icon="@drawable/ic_add_white" android:title="@string/groups_invite_members" app:showAsAction="ifRoom"/> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 6acd446ffbb73ef2b934f543b9394a7bfd6462a4..73046ee630fb995bd0a89a99a84abdee0301a15b 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -157,6 +157,7 @@ <string name="groups_create_group_button">Create Group</string> <string name="groups_create_group_invitation_button">Send Invitation</string> <string name="groups_create_group_hint">Add a name for your private group</string> + <string name="groups_invitation_sent">Group invitation has been sent</string> <string name="groups_compose_message">Compose Message</string> <string name="groups_message_sent">Message sent</string> <string name="groups_message_received">Message received</string> diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java index d2902428d660773b153a557f07cb303113046d0b..ee1ee02d592f8b47987b4d04e50202530dde7d27 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 a6a8066047e6696cc355b62682b05a447751593a..1dad3b51a36d7fd1b3426997bb270a63b5cc40e3 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<PrivateGroup, GroupMessageItem, GroupMessageHeader> 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 0000000000000000000000000000000000000000..1d29ce89d968c65f879fee2703381ac70fc1bdcd --- /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<ContactId> 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<Void, DbException>(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 d92759820b98a92c86404f8b8ca7f1de6103619a..a82b4cc1deeacd409f0c28c1c1e2552d75cf5ace 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<ContactId> 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<Void, DbException>(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 0000000000000000000000000000000000000000..7872c34cb72acc5abe01615d2f5d234ae7a85da6 --- /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; + } + +}