diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 1bb12bfff447a50c72d83e6b30d5323d9a464d08..aad00c6d9e747d81de25845bbd0493c0f2060861 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -100,6 +100,17 @@ /> </activity> + <activity + android:name=".android.privategroup.creation.CreateGroupActivity" + android:label="@string/groups_create_group_title" + android:parentActivityName=".android.NavDrawerActivity" + android:windowSoftInputMode="adjustResize"> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".android.NavDrawerActivity" + /> + </activity> + <activity android:name=".android.privategroup.conversation.GroupActivity" android:label="@string/app_name" diff --git a/briar-android/res/layout/activity_share.xml b/briar-android/res/layout/activity_share.xml deleted file mode 100644 index 80f19387f68dfda0613074f4fdc19ee32ab4b8cc..0000000000000000000000000000000000000000 --- a/briar-android/res/layout/activity_share.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<FrameLayout - android:id="@+id/shareContainer" - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent"/> \ No newline at end of file diff --git a/briar-android/res/layout/fragment_create_group.xml b/briar-android/res/layout/fragment_create_group.xml new file mode 100644 index 0000000000000000000000000000000000000000..a9601e2abbc02e615672d72bda762bc08c90a4fe --- /dev/null +++ b/briar-android/res/layout/fragment_create_group.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="@dimen/margin_medium"> + + <EditText + android:id="@+id/name" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="bottom" + android:hint="@string/groups_create_group_hint"/> + + <Button + android:id="@+id/button" + style="@style/BriarButton" + android:enabled="false" + android:text="@string/groups_create_group_button"/> + +</LinearLayout> diff --git a/briar-android/res/layout/fragment_message.xml b/briar-android/res/layout/fragment_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..168ff34a4521410e4d828751dca43f489ff1cd3b --- /dev/null +++ b/briar-android/res/layout/fragment_message.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.briarproject.android.view.LargeTextInputView + android:id="@+id/messageView" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:buttonText="@string/forum_share_button" + app:fillHeight="true" + app:hint="@string/forum_share_message"/> \ No newline at end of file diff --git a/briar-android/res/layout/fragment_share_message.xml b/briar-android/res/layout/fragment_share_message.xml deleted file mode 100644 index 45b33c0bac6aceb5c534f4847f2ac8afadcc6c30..0000000000000000000000000000000000000000 --- a/briar-android/res/layout/fragment_share_message.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - - <TextView - android:id="@+id/introductionText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="@dimen/margin_activity_horizontal" - android:text="@string/forum_share_message" - android:textColor="@color/briar_text_primary" - android:textSize="@dimen/text_size_medium"/> - - <org.briarproject.android.view.LargeTextInputView - android:id="@+id/invitationMessageView" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:gravity="bottom" - app:buttonText="@string/forum_share_button" - app:fillHeight="true" - app:hint="@string/introduction_message_hint"/> - -</LinearLayout> diff --git a/briar-android/res/menu/forum_share_actions.xml b/briar-android/res/menu/contact_selection_actions.xml similarity index 73% rename from briar-android/res/menu/forum_share_actions.xml rename to briar-android/res/menu/contact_selection_actions.xml index a3d6c154774c13dfe9d370c6eec048fc38dcb7b0..fbef25059b583515e0a331941059f8a5893c9f3d 100644 --- a/briar-android/res/menu/forum_share_actions.xml +++ b/briar-android/res/menu/contact_selection_actions.xml @@ -4,9 +4,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/action_share_forum" + android:id="@+id/action_contacts_selected" android:icon="@drawable/ic_check_white" - android:title="@string/forum_share_action" + android:title="@string/contacts_selected" app:showAsAction="always"/> </menu> \ No newline at end of file diff --git a/briar-android/res/menu/groups_list_actions.xml b/briar-android/res/menu/groups_list_actions.xml index 511224ff1650225e103d86b24531ea559da54bcf..16eeba4625ce8a78907e35818f693ef191560154 100644 --- a/briar-android/res/menu/groups_list_actions.xml +++ b/briar-android/res/menu/groups_list_actions.xml @@ -6,7 +6,7 @@ <item android:id="@+id/action_add_group" android:icon="@drawable/ic_add_white" - android:title="@string/groups_add_group_title" + android:title="@string/groups_create_group_title" app:showAsAction="ifRoom"/> </menu> \ No newline at end of file diff --git a/briar-android/res/values-de/strings.xml b/briar-android/res/values-de/strings.xml index 2967f16b1993290d636d1f4ed594cba6fd448105..e3f45375514005cfc8cebc11090704b1bdbed01c 100644 --- a/briar-android/res/values-de/strings.xml +++ b/briar-android/res/values-de/strings.xml @@ -171,7 +171,7 @@ <string name="forum_left_toast">Forum wurde verlassen</string> <!--Forum Sharing--> <string name="forum_share_button">Forum teilen</string> - <string name="forum_share_action">Teile dieses Forum mit den gewählten Kontakten</string> + <string name="contacts_selected">Teile dieses Forum mit den gewählten Kontakten</string> <string name="activity_share_toolbar_header">Kontakte auswählen</string> <string name="no_contacts_selector">Du scheinst hier neu zu sein und noch keine Kontakte zu haben.\n\nBitte komm zurück, wenn du deinen ersten Kontakt hinzugefügt hast.</string> <string name="forum_shared_snackbar">Forum mit gewählten Kontakten geteilt</string> diff --git a/briar-android/res/values-es/strings.xml b/briar-android/res/values-es/strings.xml index 521fbd9f866aa42481062518bcb255069fdb86c9..63135b3bf91dcf4f93c2ddeb1e442975b9e70d39 100644 --- a/briar-android/res/values-es/strings.xml +++ b/briar-android/res/values-es/strings.xml @@ -159,7 +159,7 @@ <string name="forum_left_toast">Foro abandonado</string> <!--Forum Sharing--> <string name="forum_share_button">Compartir foro</string> - <string name="forum_share_action">Compartir este foro con los contactos seleccionados</string> + <string name="contacts_selected">Compartir este foro con los contactos seleccionados</string> <string name="activity_share_toolbar_header">Elige contactos</string> <string name="no_contacts_selector">Parece que eres nuevo aquà y no tienes contactos aún.\n\nPor favor, vuelve cuando hayas añadido tu primer contacto.</string> <string name="forum_shared_snackbar">Foro compartido con los contactos seleccionados</string> diff --git a/briar-android/res/values-it/strings.xml b/briar-android/res/values-it/strings.xml index 28a764499d57e3310eac59bef28c39c07e69d34a..e7b7a678f8b5c689dc1e47e8110c85a28bbcabfd 100644 --- a/briar-android/res/values-it/strings.xml +++ b/briar-android/res/values-it/strings.xml @@ -136,7 +136,7 @@ <string name="forum_left_toast">Forum lasciato</string> <!--Forum Sharing--> <string name="forum_share_button">Condividi Forum</string> - <string name="forum_share_action">Condividi questo forum con i contatti scelti</string> + <string name="contacts_selected">Condividi questo forum con i contatti scelti</string> <string name="activity_share_toolbar_header">Scegli Contatti</string> <string name="forum_shared_snackbar">Forum condiviso con i contatti scelti</string> <string name="forum_share_error">C\'è stato un errore nella condivisione di questo forum.</string> diff --git a/briar-android/res/values-pt-rBR/strings.xml b/briar-android/res/values-pt-rBR/strings.xml index 4fd4eb8c7bad47344326c2ef7932251405d9a96d..75d4cc14b4edd7d34a3c5f67e2d9e9140b999c18 100644 --- a/briar-android/res/values-pt-rBR/strings.xml +++ b/briar-android/res/values-pt-rBR/strings.xml @@ -171,7 +171,7 @@ Se sentido sozinho aqui? Compartilhe esse fórum com seus contatos!</string> <string name="forum_left_toast">Saiu do fórum</string> <!--Forum Sharing--> <string name="forum_share_button">Compartilhar fórum</string> - <string name="forum_share_action">Compartilhar este fórum com os contatos escolhidos</string> + <string name="contacts_selected">Compartilhar este fórum com os contatos escolhidos</string> <string name="activity_share_toolbar_header">Escolher contatos</string> <string name="no_contacts_selector">Parece que você é novo aqui e não tem nenhum contato ainda. Por favor volte aqui depois de adicionar um contato.</string> diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index b1652f5fb7c1ea51c54367e5d0137ac4bdc99d83..872800c9f05297d0fa40ae400567dfe9d37069da 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -155,8 +155,11 @@ <string name="groups_group_is_empty">This group is empty</string> <string name="groups_group_is_dissolved">This group is dissolved</string> <string name="groups_remove">Remove</string> - <string name="groups_add_group_title">Add Private Group</string> + <string name="groups_create_group_title">Create Private Group</string> <string name="groups_no_messages">This group is empty.\n\nYou can use the pen icon at the top to compose the first message.</string> + <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_compose_message">Compose Message</string> <string name="groups_message_sent">Message sent</string> <string name="groups_message_received">Message received</string> @@ -195,7 +198,7 @@ <!-- Forum Sharing --> <string name="forum_share_button">Share Forum</string> - <string name="forum_share_action">Share this forum with chosen contacts</string> + <string name="contacts_selected">Contacts selected</string> <string name="activity_share_toolbar_header">Choose Contacts</string> <string name="no_contacts_selector">It seems that you are new here and have no contacts yet.\n\nPlease come back here after you added your first contact.</string> <string name="forum_shared_snackbar">Forum shared with chosen contacts</string> diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java index 4e66c87aba6e1fbb891dc9e669d55348a8df974a..1179905b6932ced492c512debc964cc53d0ff76a 100644 --- a/briar-android/src/org/briarproject/android/ActivityComponent.java +++ b/briar-android/src/org/briarproject/android/ActivityComponent.java @@ -28,7 +28,10 @@ import org.briarproject.android.keyagreement.KeyAgreementActivity; import org.briarproject.android.keyagreement.ShowQrCodeFragment; import org.briarproject.android.panic.PanicPreferencesActivity; import org.briarproject.android.panic.PanicResponderActivity; +import org.briarproject.android.privategroup.creation.CreateGroupActivity; +import org.briarproject.android.privategroup.creation.CreateGroupFragment; import org.briarproject.android.privategroup.conversation.GroupActivity; +import org.briarproject.android.privategroup.creation.CreateGroupMessageFragment; import org.briarproject.android.privategroup.list.GroupListFragment; import org.briarproject.android.sharing.ContactSelectorFragment; import org.briarproject.android.sharing.InvitationsBlogActivity; @@ -73,6 +76,8 @@ public interface ActivityComponent { void inject(InvitationsBlogActivity activity); + void inject(CreateGroupActivity activity); + void inject(GroupActivity activity); void inject(CreateForumActivity activity); @@ -118,6 +123,8 @@ public interface ActivityComponent { // Fragments void inject(ContactListFragment fragment); + void inject(CreateGroupFragment fragment); + void inject(CreateGroupMessageFragment fragment); void inject(GroupListFragment fragment); void inject(ForumListFragment fragment); void inject(FeedFragment fragment); diff --git a/briar-android/src/org/briarproject/android/ActivityModule.java b/briar-android/src/org/briarproject/android/ActivityModule.java index 07cace566205890ee8a101bd04e8a9f651baa94b..69505d32f3ea0d2f7bbef96cd5e21e97470dc57b 100644 --- a/briar-android/src/org/briarproject/android/ActivityModule.java +++ b/briar-android/src/org/briarproject/android/ActivityModule.java @@ -23,6 +23,8 @@ import org.briarproject.android.forum.ForumController; import org.briarproject.android.forum.ForumControllerImpl; import org.briarproject.android.privategroup.conversation.GroupController; import org.briarproject.android.privategroup.conversation.GroupControllerImpl; +import org.briarproject.android.privategroup.creation.CreateGroupController; +import org.briarproject.android.privategroup.creation.CreateGroupControllerImpl; import org.briarproject.android.privategroup.list.GroupListController; import org.briarproject.android.privategroup.list.GroupListControllerImpl; @@ -101,6 +103,13 @@ public class ActivityModule { return groupListController; } + @ActivityScope + @Provides + protected CreateGroupController provideCreateGroupController( + CreateGroupControllerImpl createGroupController) { + return createGroupController; + } + @ActivityScope @Provides protected GroupController provideGroupController( diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java index 04ee0a747db6aac0901c0e381ff2d823f15a797c..9e2db81dc85c5cf54e9831f5902e1ee5fc2b1f15 100644 --- a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java @@ -5,7 +5,6 @@ import android.support.annotation.CallSuper; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; @@ -36,8 +35,6 @@ abstract class BasePostFragment extends BaseFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - view = inflater.inflate(R.layout.fragment_blog_post, container, false); progressBar = (ProgressBar) view.findViewById(R.id.progressBar); @@ -60,17 +57,6 @@ abstract class BasePostFragment extends BaseFragment { stopPeriodicUpdate(); } - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - getActivity().onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - @UiThread protected void onBlogPostLoaded(BlogPostItem post) { progressBar.setVisibility(INVISIBLE); diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index eb655209108c6a290394c31c3fc3241d4f711c12..8809864d55e7103f684d1262bfcf017752b4a342 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -80,9 +80,6 @@ public class BlogFragment extends BaseFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - setHasOptionsMenu(true); - Bundle args = getArguments(); byte[] b = args.getByteArray(GROUP_ID); if (b == null) throw new IllegalStateException("No group ID in args"); @@ -151,9 +148,6 @@ public class BlogFragment extends BaseFragment implements android.R.anim.slide_in_left, android.R.anim.slide_out_right); switch (item.getItemId()) { - case android.R.id.home: - getActivity().onBackPressed(); - return true; case R.id.action_write_blog_post: Intent i = new Intent(getActivity(), WriteBlogPostActivity.class); diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index 9545f34ff4c8f7fe58e7d431bcb501269b01ab0d..4be0bc5413403741fed04e20a4dbf21f5be73129 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -66,7 +66,6 @@ public class FeedFragment extends BaseFragment implements public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); View v = inflater.inflate(R.layout.fragment_blog, container, false); adapter = new BlogPostAdapter(getActivity(), this); diff --git a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java index e3d50dfeefa8d288cc2e67477f04937784d6732a..479fecaadaff9cfaeea1b394f8faa64983ed07b2 100644 --- a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java @@ -72,8 +72,6 @@ public class ReblogFragment extends BaseFragment implements TextInputListener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - Bundle args = getArguments(); blogId = new GroupId(args.getByteArray(GROUP_ID)); postId = new MessageId(args.getByteArray(POST_ID)); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index 474b2cc2b7b7b7f854541eb1128776378b266679..fe1e62a4da2244079eeb01d04c9fb1d8604ecacc 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -106,8 +106,6 @@ public class ContactListFragment extends BaseFragment implements EventListener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - View contentView = inflater.inflate(R.layout.list, container, false); diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index e52bc4a89d0ec2b9b542b71e39906b153dfe7748..a5496d9c709b464113bfc49999552d9427ab8b2f 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -623,6 +623,7 @@ public class ConversationActivity extends BriarActivity long timestamp = System.currentTimeMillis(); timestamp = Math.max(timestamp, getMinTimestampForNewMessage()); createMessage(StringUtils.toUtf8(text), timestamp); + textInputView.setText(""); } private long getMinTimestampForNewMessage() { diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index 6bbf1965776b3ea3c90c7eccce1b2d661d89282c..f1faecd46d260908e5c7b7e89428df6b2aed2b8b 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -78,8 +78,6 @@ public class ForumListFragment extends BaseEventFragment implements public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - View contentView = inflater.inflate(R.layout.fragment_forum_list, container, false); diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java index 2cb6b13e6152d89b1e118e8b2cd8494559e78b26..223c01367e28fb25a7a49b9e204941cca5c8f61e 100644 --- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.support.v4.app.Fragment; +import android.view.MenuItem; import org.briarproject.android.ActivityComponent; import org.briarproject.android.DestroyableContext; @@ -27,6 +28,9 @@ public abstract class BaseFragment extends Fragment @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // allow for "up" button to act as back button + setHasOptionsMenu(true); } @@ -37,6 +41,17 @@ public abstract class BaseFragment extends Fragment listener.onFragmentCreated(getUniqueTag()); } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + listener.onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + @UiThread protected void finish() { getActivity().supportFinishAfterTransition(); @@ -47,6 +62,9 @@ public abstract class BaseFragment extends Fragment @Deprecated void runOnDbThread(Runnable runnable); + @UiThread + void onBackPressed(); + @UiThread ActivityComponent getActivityComponent(); diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java index 019aff689978c3354668d9af1e38cfebc26d8768..f5c9c32a635bead8e019289a12515f62f1964471 100644 --- a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java +++ b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java @@ -14,6 +14,7 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.view.TextInputView; +import org.briarproject.android.view.TextInputView.TextInputListener; import org.briarproject.api.FormatException; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -37,7 +38,7 @@ import static java.util.logging.Level.WARNING; import static org.briarproject.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH; public class IntroductionMessageFragment extends BaseFragment - implements TextInputView.TextInputListener { + implements TextInputListener { public static final String TAG = IntroductionMessageFragment.class.getName(); @@ -56,7 +57,8 @@ public class IntroductionMessageFragment extends BaseFragment @Inject protected volatile IntroductionManager introductionManager; - public static IntroductionMessageFragment newInstance(int contactId1, int contactId2) { + public static IntroductionMessageFragment newInstance(int contactId1, + int contactId2) { Bundle args = new Bundle(); args.putInt(CONTACT_ID_1, contactId1); args.putInt(CONTACT_ID_2, contactId2); diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..355de7c274ddfd0f1d978dd5eb8ad29533bae1da --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupActivity.java @@ -0,0 +1,165 @@ +package org.briarproject.android.privategroup.creation; + +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.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 + CreateGroupListener, MessageFragmentListener { + + @Inject + CreateGroupController controller; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + 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 + public void onBackPressed() { + if (getSupportFragmentManager().getBackStackEntryCount() == 1) { + // At this point, the group had been created already, + // so don't allow to create it again. + openNewGroup(); + } else { + super.onBackPressed(); + } + } + + @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, + new UiResultExceptionHandler<GroupId, DbException>(this) { + @Override + public void onResultUi(GroupId g) { + switchToContactSelectorFragment(g); + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO proper error handling + finish(); + } + }); + } + + private void switchToContactSelectorFragment(GroupId g) { + ContactSelectorFragment fragment = + ContactSelectorFragment.newInstance(g); + 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 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()); + ActivityOptionsCompat options = + makeCustomAnimation(this, android.R.anim.fade_in, + android.R.anim.fade_out); + ActivityCompat.startActivity(this, i, options.toBundle()); + // finish this activity, so we can't come back to it + finish(); + } + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupController.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupController.java new file mode 100644 index 0000000000000000000000000000000000000000..da1a00a0d1275559ebdb13272a91d626ef27fffb --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupController.java @@ -0,0 +1,19 @@ +package org.briarproject.android.privategroup.creation; + +import org.briarproject.android.controller.DbController; +import org.briarproject.android.controller.handler.ResultExceptionHandler; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sync.GroupId; + +import java.util.Collection; + +public interface CreateGroupController extends DbController { + + void createGroup(String name, + ResultExceptionHandler<GroupId, DbException> result); + + void sendInvitation(GroupId groupId, Collection<ContactId> contacts, + String message, ResultExceptionHandler<Void, DbException> result); + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupControllerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a35c2ac20435a7486ecbc1407989c3216d1b42e1 --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupControllerImpl.java @@ -0,0 +1,68 @@ +package org.briarproject.android.privategroup.creation; + +import org.briarproject.android.controller.DbControllerImpl; +import org.briarproject.android.controller.handler.ResultExceptionHandler; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DatabaseExecutor; +import org.briarproject.api.db.DbException; +import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.privategroup.PrivateGroupManager; +import org.briarproject.api.sync.GroupId; + +import java.util.Collection; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; + +public class CreateGroupControllerImpl extends DbControllerImpl + implements CreateGroupController { + + private static final Logger LOG = + Logger.getLogger(CreateGroupControllerImpl.class.getName()); + + private final PrivateGroupManager groupManager; + + @Inject + CreateGroupControllerImpl(@DatabaseExecutor Executor dbExecutor, + LifecycleManager lifecycleManager, + PrivateGroupManager groupManager) { + super(dbExecutor, lifecycleManager); + this.groupManager = groupManager; + } + + @Override + public void createGroup(final String name, + final ResultExceptionHandler<GroupId, DbException> handler) { + runOnDbThread(new Runnable() { + @Override + public void run() { + LOG.info("Adding group to database..."); + try { + handler.onResult(groupManager.addPrivateGroup(name)); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + handler.onException(e); + } + } + }); + } + + @Override + public void sendInvitation(final GroupId groupId, + final Collection<ContactId> contacts, final String message, + final ResultExceptionHandler<Void, DbException> result) { + runOnDbThread(new Runnable() { + @Override + public void run() { + // TODO actually send invitation + //noinspection ConstantConditions + result.onResult(null); + } + }); + } + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupFragment.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..7f21508e38d1fc0f27b66ce6f08c3bed42780447 --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupFragment.java @@ -0,0 +1,93 @@ +package org.briarproject.android.privategroup.creation; + +import android.content.Context; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; + +import org.briarproject.R; +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.fragment.BaseFragment; + +import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; + +public class CreateGroupFragment extends BaseFragment { + + public final static String TAG = CreateGroupFragment.class.getName(); + + private CreateGroupListener listener; + private EditText name; + private Button button; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (CreateGroupListener) context; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + // inflate view + View v = inflater.inflate(R.layout.fragment_create_group, container, + false); + name = (EditText) v.findViewById(R.id.name); + name.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + validateName(); + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + button = (Button) v.findViewById(R.id.button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + listener.hideSoftKeyboard(name); + listener.onGroupNameChosen(name.getText().toString()); + } + }); + + return v; + } + + @Override + public void onStart() { + super.onStart(); + listener.showSoftKeyboard(name); + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + + @Override + public String getUniqueTag() { + return TAG; + } + + private void validateName() { + String name = this.name.getText().toString(); + if (name.length() < 1 || name.length() > MAX_GROUP_NAME_LENGTH) + button.setEnabled(false); + else if(!button.isEnabled()) + button.setEnabled(true); + } + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupListener.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupListener.java new file mode 100644 index 0000000000000000000000000000000000000000..3347be1586748e6d63e9098deb407f481302d2dd --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupListener.java @@ -0,0 +1,15 @@ +package org.briarproject.android.privategroup.creation; + +import android.view.View; + +import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; + +interface CreateGroupListener extends BaseFragmentListener { + + void onGroupNameChosen(String name); + + void showSoftKeyboard(View view); + + void hideSoftKeyboard(View view); + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupMessageFragment.java b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupMessageFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..a261ce0167313adb3b10585127d2fcfc2856aa0e --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/creation/CreateGroupMessageFragment.java @@ -0,0 +1,36 @@ +package org.briarproject.android.privategroup.creation; + +import android.support.annotation.StringRes; + +import org.briarproject.R; +import org.briarproject.android.ActivityComponent; +import org.briarproject.android.sharing.BaseMessageFragment; + +public class CreateGroupMessageFragment extends BaseMessageFragment { + + private final static String TAG = + CreateGroupMessageFragment.class.getName(); + + @Override + @StringRes + protected int getButtonText() { + return R.string.groups_create_group_invitation_button; + } + + @Override + @StringRes + protected int getHintText() { + return R.string.forum_share_message; + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + } + +} diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java index 4489dd6bf003aa9829dc0d2fcd6d4e8ef5f438d2..9e77003acedb1f79f17c76cac2df0309848ed2ad 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java @@ -1,8 +1,10 @@ package org.briarproject.android.privategroup.list; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.UiThread; +import android.support.v4.app.ActivityOptionsCompat; import android.support.v7.widget.LinearLayoutManager; import android.view.LayoutInflater; import android.view.Menu; @@ -15,6 +17,7 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.android.privategroup.creation.CreateGroupActivity; import org.briarproject.android.privategroup.list.GroupListController.GroupListListener; import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener; import org.briarproject.android.view.BriarRecyclerView; @@ -27,6 +30,8 @@ import java.util.logging.Logger; import javax.inject.Inject; +import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation; + public class GroupListFragment extends BaseFragment implements GroupListListener, OnGroupRemoveClickListener { @@ -48,8 +53,6 @@ public class GroupListFragment extends BaseFragment implements public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - setHasOptionsMenu(true); - View v = inflater.inflate(R.layout.list, container, false); adapter = new GroupListAdapter(getContext(), this); @@ -94,7 +97,12 @@ public class GroupListFragment extends BaseFragment implements public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_add_group: - // TODO + Intent i = new Intent(getContext(), CreateGroupActivity.class); + ActivityOptionsCompat options = + makeCustomAnimation(getActivity(), + android.R.anim.slide_in_left, + android.R.anim.slide_out_right); + startActivity(i, options.toBundle()); return true; default: return super.onOptionsItemSelected(item); diff --git a/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..eb05d19bcf5bc89659b711cb6b1549b5b0da6ab2 --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/BaseMessageFragment.java @@ -0,0 +1,98 @@ +package org.briarproject.android.sharing; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.support.design.widget.Snackbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.R; +import org.briarproject.android.fragment.BaseFragment; +import org.briarproject.android.view.LargeTextInputView; +import org.briarproject.android.view.TextInputView.TextInputListener; +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.briarproject.util.StringUtils; + +import static android.support.design.widget.Snackbar.LENGTH_SHORT; +import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; +import static org.briarproject.util.StringUtils.truncateUtf8; + +public abstract class BaseMessageFragment extends BaseFragment + implements TextInputListener { + + protected LargeTextInputView message; + private MessageFragmentListener listener; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = (MessageFragmentListener) context; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + // inflate view + View v = inflater.inflate(R.layout.fragment_message, container, + false); + message = (LargeTextInputView) v.findViewById(R.id.messageView); + message.setButtonText(getString(getButtonText())); + message.setHint(getHintText()); + message.setListener(this); + + return v; + } + + protected void setTitle(int res) { + listener.setTitle(res); + } + + @StringRes + protected abstract int getButtonText(); + @StringRes + protected abstract int getHintText(); + + @Override + public void onStart() { + super.onStart(); + message.showSoftKeyboard(); + } + + @Override + public void onSendClick(String msg) { + if (StringUtils.isTooLong(msg, listener.getMaximumMessageLength())) { + Snackbar.make(message, R.string.text_too_long, LENGTH_SHORT).show(); + return; + } + + // disable button to prevent accidental double actions + message.setSendButtonEnabled(false); + message.hideSoftKeyboard(); + + msg = truncateUtf8(msg, MAX_INVITATION_MESSAGE_LENGTH); + if(!listener.onButtonClick(msg)) { + message.setSendButtonEnabled(true); + message.showSoftKeyboard(); + } + } + + @UiThread + @NotNullByDefault + public interface MessageFragmentListener { + + void onBackPressed(); + + void setTitle(@StringRes int titleRes); + + /** Returns true when the button click has been consumed. */ + boolean onButtonClick(String message); + + int getMaximumMessageLength(); + + } + +} diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorActivity.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..2dad460eae6a37d1599d94dd428971843b771f0a --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorActivity.java @@ -0,0 +1,90 @@ +package org.briarproject.android.sharing; + +import android.os.Bundle; +import android.support.annotation.CallSuper; +import android.support.annotation.UiThread; + +import org.briarproject.R; +import org.briarproject.android.BriarActivity; +import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener; +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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public abstract class ContactSelectorActivity extends BriarActivity implements + BaseFragmentListener, ContactSelectorListener { + + final static String CONTACTS = "contacts"; + + protected GroupId groupId; + protected Collection<ContactId> contacts; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + setContentView(R.layout.activity_fragment_container); + + if (bundle != null) { + ArrayList<Integer> intContacts = + bundle.getIntegerArrayList(CONTACTS); + if (intContacts != null) { + contacts = getContactsFromIntegers(intContacts); + } + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (contacts != null) { + outState.putIntegerArrayList(CONTACTS, + getContactsFromIds(contacts)); + } + } + + @CallSuper + @UiThread + @Override + public void contactsSelected(GroupId groupId, + Collection<ContactId> contacts) { + this.groupId = groupId; + this.contacts = contacts; + } + + @DatabaseExecutor + public abstract boolean isDisabled(GroupId groupId, Contact c) + throws DbException; + + static ArrayList<Integer> getContactsFromIds( + Collection<ContactId> contacts) { + // transform ContactIds to Integers so they can be added to a bundle + ArrayList<Integer> intContacts = new ArrayList<>(contacts.size()); + for (ContactId contactId : contacts) { + intContacts.add(contactId.getInt()); + } + return intContacts; + } + + static Collection<ContactId> getContactsFromIntegers( + ArrayList<Integer> intContacts) { + // turn contact integers from a bundle back to ContactIds + List<ContactId> contacts = new ArrayList<>(intContacts.size()); + for (Integer c : intContacts) { + contacts.add(new ContactId(c)); + } + return contacts; + } + + @Override + public void onFragmentCreated(String tag) { + + } + +} diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java index 82db75adf15b2ad6ab70e893935628d68601cf9a..03e4da3979fc6de40030705c21b01e471f532ab1 100644 --- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java @@ -23,7 +23,6 @@ import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.db.DbException; -import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.GroupId; @@ -48,7 +47,6 @@ public class ContactSelectorFragment extends BaseFragment implements public static final String TAG = ContactSelectorFragment.class.getName(); private static final Logger LOG = Logger.getLogger(TAG); - private ShareActivity shareActivity; private Menu menu; private BriarRecyclerView list; private ContactSelectorAdapter adapter; @@ -59,13 +57,11 @@ public class ContactSelectorFragment extends BaseFragment implements volatile ContactManager contactManager; @Inject volatile IdentityManager identityManager; - @Inject - volatile ForumSharingManager forumSharingManager; private volatile GroupId groupId; + private volatile ContactSelectorListener listener; public static ContactSelectorFragment newInstance(GroupId groupId) { - Bundle args = new Bundle(); args.putByteArray(GROUP_ID, groupId.getBytes()); ContactSelectorFragment fragment = new ContactSelectorFragment(); @@ -81,14 +77,13 @@ public class ContactSelectorFragment extends BaseFragment implements @Override public void onAttach(Context context) { super.onAttach(context); - shareActivity = (ShareActivity) context; + listener = (ContactSelectorListener) context; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setHasOptionsMenu(true); Bundle args = getArguments(); byte[] b = args.getByteArray(GROUP_ID); if (b == null) throw new IllegalStateException("No GroupId"); @@ -139,6 +134,7 @@ public class ContactSelectorFragment extends BaseFragment implements @Override public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); if (adapter != null) { selectedContacts = adapter.getSelectedContactIds(); outState.putIntegerArrayList(CONTACTS, @@ -148,7 +144,7 @@ public class ContactSelectorFragment extends BaseFragment implements @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.forum_share_actions, menu); + inflater.inflate(R.menu.contact_selection_actions, menu); super.onCreateOptionsMenu(menu, inflater); this.menu = menu; // hide sharing action initially, if no contact is selected @@ -159,12 +155,9 @@ public class ContactSelectorFragment extends BaseFragment implements public boolean onOptionsItemSelected(final MenuItem item) { // Handle presses on the action bar items switch (item.getItemId()) { - case android.R.id.home: - shareActivity.onBackPressed(); - return true; - case R.id.action_share_forum: + case R.id.action_contacts_selected: selectedContacts = adapter.getSelectedContactIds(); - shareActivity.showMessageScreen(groupId, selectedContacts); + listener.contactsSelected(groupId, selectedContacts); return true; default: return super.onOptionsItemSelected(item); @@ -185,7 +178,7 @@ public class ContactSelectorFragment extends BaseFragment implements } private void loadContacts(@Nullable final Collection<ContactId> selection) { - shareActivity.runOnDbThread(new Runnable() { + listener.runOnDbThread(new Runnable() { @Override public void run() { try { @@ -199,7 +192,7 @@ public class ContactSelectorFragment extends BaseFragment implements boolean selected = selection != null && selection.contains(c.getId()); // do we have already some sharing with that contact? - boolean disabled = shareActivity.isDisabled(groupId, c); + boolean disabled = listener.isDisabled(groupId, c); contacts.add(new SelectableContactListItem(c, localAuthor, groupId, selected, disabled)); } @@ -216,7 +209,7 @@ public class ContactSelectorFragment extends BaseFragment implements } private void displayContacts(final List<ContactListItem> contacts) { - shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { if (contacts.isEmpty()) list.showData(); @@ -228,7 +221,7 @@ public class ContactSelectorFragment extends BaseFragment implements private void updateMenuItem() { if (menu == null) return; - MenuItem item = menu.findItem(R.id.action_share_forum); + MenuItem item = menu.findItem(R.id.action_contacts_selected); if (item == null) return; selectedContacts = adapter.getSelectedContactIds(); diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorListener.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorListener.java new file mode 100644 index 0000000000000000000000000000000000000000..8016c45e9050d5c69843afa8c73bb100b8e3cf3b --- /dev/null +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorListener.java @@ -0,0 +1,28 @@ +package org.briarproject.android.sharing; + +import android.support.annotation.UiThread; + +import org.briarproject.android.DestroyableContext; +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 java.util.Collection; + +public interface ContactSelectorListener extends DestroyableContext { + + @Deprecated + void runOnDbThread(Runnable runnable); + + @DatabaseExecutor + boolean isDisabled(GroupId groupId, Contact c) throws DbException; + + @UiThread + void contactsSelected(GroupId groupId, Collection<ContactId> contacts); + + @UiThread + void onBackPressed(); + +} diff --git a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java index d79a7ed2eee4ae5141a8020c45f211e6a1eee627..e89fe277e1251b88c9cdbffe644fbfafbdc92697 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java @@ -2,96 +2,110 @@ package org.briarproject.android.sharing; import android.content.Intent; import android.os.Bundle; -import android.view.View; +import android.support.annotation.StringRes; +import android.support.annotation.UiThread; +import android.widget.Toast; import org.briarproject.R; -import org.briarproject.android.BriarActivity; -import org.briarproject.android.fragment.BaseFragment; -import org.briarproject.api.contact.Contact; +import org.briarproject.android.sharing.BaseMessageFragment.MessageFragmentListener; 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.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.logging.Logger; -public abstract class ShareActivity extends BriarActivity implements - BaseFragment.BaseFragmentListener { +import static android.widget.Toast.LENGTH_SHORT; +import static java.util.logging.Level.WARNING; - final static String CONTACTS = "contacts"; +public abstract class ShareActivity extends ContactSelectorActivity implements + MessageFragmentListener { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + private final static Logger LOG = + Logger.getLogger(ShareActivity.class.getName()); - setContentView(R.layout.activity_share); + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); Intent i = getIntent(); byte[] b = i.getByteArrayExtra(GROUP_ID); if (b == null) throw new IllegalStateException("No GroupId"); - GroupId groupId = new GroupId(b); + groupId = new GroupId(b); - if (savedInstanceState == null) { + if (bundle == null) { ContactSelectorFragment contactSelectorFragment = ContactSelectorFragment.newInstance(groupId); getSupportFragmentManager().beginTransaction() - .add(R.id.shareContainer, contactSelectorFragment) + .add(R.id.fragmentContainer, contactSelectorFragment) .commit(); } } - abstract ShareMessageFragment getMessageFragment(GroupId groupId, - Collection<ContactId> contacts); - - abstract boolean isDisabled(GroupId groupId, Contact c) throws DbException; - - void showMessageScreen(GroupId groupId, Collection<ContactId> contacts) { - ShareMessageFragment messageFragment = - getMessageFragment(groupId, contacts); + @UiThread + @Override + public void contactsSelected(GroupId groupId, + Collection<ContactId> contacts) { + super.contactsSelected(groupId, contacts); + BaseMessageFragment messageFragment = getMessageFragment(); 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.shareContainer, messageFragment, + .replace(R.id.fragmentContainer, messageFragment, ContactSelectorFragment.TAG) .addToBackStack(null) .commit(); } - static ArrayList<Integer> getContactsFromIds( - Collection<ContactId> contacts) { - - // transform ContactIds to Integers so they can be added to a bundle - ArrayList<Integer> intContacts = new ArrayList<>(contacts.size()); - for (ContactId contactId : contacts) { - intContacts.add(contactId.getInt()); - } - return intContacts; - } + abstract BaseMessageFragment getMessageFragment(); - void sharingSuccessful(View v) { + @UiThread + @Override + public boolean onButtonClick(@NotNull String message) { + share(groupId, contacts, message); setResult(RESULT_OK); - hideSoftKeyboard(v); supportFinishAfterTransition(); + return true; } - static Collection<ContactId> getContactsFromIntegers( - ArrayList<Integer> intContacts) { - - // turn contact integers from a bundle back to ContactIds - List<ContactId> contacts = new ArrayList<>(intContacts.size()); - for (Integer c : intContacts) { - contacts.add(new ContactId(c)); - } - return contacts; + private void share(final GroupId g, final Collection<ContactId> contacts, + final String msg) { + runOnDbThread(new Runnable() { + @Override + public void run() { + try { + for (ContactId c : contacts) { + share(g, c, msg); + } + } catch (DbException e) { + // TODO proper error handling + sharingError(); + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); } - @Override - public void onFragmentCreated(String tag) { - + @DatabaseExecutor + protected abstract void share(GroupId g, ContactId c, String msg) + throws DbException; + + private void sharingError() { + runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + int res = getSharingError(); + Toast.makeText(ShareActivity.this, res, LENGTH_SHORT).show(); + } + }); } + protected abstract @StringRes int getSharingError(); + } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java index 696ea145228995a4a8bffbbb8b87b4df1813bd5b..7d5cdeef3e63ae5e211dc9dabbe283bafd0f654f 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java @@ -1,5 +1,6 @@ package org.briarproject.android.sharing; +import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.contact.Contact; @@ -7,18 +8,19 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; -import java.util.Collection; - import javax.inject.Inject; +import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; + public class ShareBlogActivity extends ShareActivity { + // Fields that are accessed from background threads must be volatile @Inject volatile BlogSharingManager blogSharingManager; - ShareMessageFragment getMessageFragment(GroupId groupId, - Collection<ContactId> contacts) { - return ShareBlogMessageFragment.newInstance(groupId, contacts); + @Override + BaseMessageFragment getMessageFragment() { + return ShareBlogMessageFragment.newInstance(); } @Override @@ -26,10 +28,24 @@ public class ShareBlogActivity extends ShareActivity { component.inject(this); } - /** - * This must only be called from a DbThread - */ - boolean isDisabled(GroupId groupId, Contact c) throws DbException { + @Override + public boolean isDisabled(GroupId groupId, Contact c) throws DbException { return !blogSharingManager.canBeShared(groupId, c); } + + @Override + protected void share(GroupId g, ContactId c, String msg) + throws DbException { + blogSharingManager.sendInvitation(g, c, msg); + } + + @Override + protected int getSharingError() { + return R.string.blogs_sharing_error; + } + + @Override + public int getMaximumMessageLength() { + return MAX_MESSAGE_BODY_LENGTH; + } } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java index d9f944ab0c91654912f33c1797d34a67cffbfabd..ccee4d8fecb028dcbf9e2ec970fd2115f7e5c2af 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java @@ -1,41 +1,20 @@ package org.briarproject.android.sharing; import android.os.Bundle; +import android.support.annotation.StringRes; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.api.blogs.BlogSharingManager; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.db.DbException; -import org.briarproject.api.sync.GroupId; -import java.util.Collection; -import java.util.logging.Logger; - -import javax.inject.Inject; - -import static android.widget.Toast.LENGTH_SHORT; -import static java.util.logging.Level.WARNING; - -public class ShareBlogMessageFragment extends ShareMessageFragment { +public class ShareBlogMessageFragment extends BaseMessageFragment { public final static String TAG = ShareBlogMessageFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); - - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile BlogSharingManager blogSharingManager; - public static ShareBlogMessageFragment newInstance(GroupId groupId, - Collection<ContactId> contacts) { - - ShareBlogMessageFragment fragment = new ShareBlogMessageFragment(); - fragment.setArguments(getArguments(groupId, contacts)); - return fragment; + public static ShareBlogMessageFragment newInstance() { + return new ShareBlogMessageFragment(); } @Override @@ -43,48 +22,29 @@ public class ShareBlogMessageFragment extends ShareMessageFragment { Bundle savedInstanceState) { setTitle(R.string.blogs_sharing_share); - - View v = super.onCreateView(inflater, container, savedInstanceState); - ui.message.setButtonText(getString(R.string.blogs_sharing_button)); - return v; + return super.onCreateView(inflater, container, savedInstanceState); } @Override - public void injectFragment(ActivityComponent component) { - component.inject(this); + @StringRes + protected int getButtonText() { + return R.string.blogs_sharing_button; } @Override - public String getUniqueTag() { - return TAG; + @StringRes + protected int getHintText() { + return R.string.forum_share_message; } @Override - protected void share(final String msg) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - for (ContactId c : getContacts()) { - blogSharingManager.sendInvitation(getGroupId(), c, msg); - } - } catch (DbException e) { - sharingError(); - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); + public void injectFragment(ActivityComponent component) { + component.inject(this); } @Override - protected void sharingError() { - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - int res = R.string.blogs_sharing_error; - Toast.makeText(getContext(), res, LENGTH_SHORT).show(); - } - }); + public String getUniqueTag() { + return TAG; } + } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java index 51a5d5a22ae80e96be3c815faee189bb5d9a9763..492e3615b23b4903a61d433d04779170e7e557f4 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java @@ -1,5 +1,6 @@ package org.briarproject.android.sharing; +import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; @@ -7,17 +8,19 @@ import org.briarproject.api.db.DbException; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.sync.GroupId; -import java.util.Collection; - import javax.inject.Inject; +import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; + public class ShareForumActivity extends ShareActivity { + + // Fields that are accessed from background threads must be volatile @Inject volatile ForumSharingManager forumSharingManager; - ShareMessageFragment getMessageFragment(GroupId groupId, - Collection<ContactId> contacts) { - return ShareForumMessageFragment.newInstance(groupId, contacts); + @Override + BaseMessageFragment getMessageFragment() { + return ShareForumMessageFragment.newInstance(); } @Override @@ -25,10 +28,24 @@ public class ShareForumActivity extends ShareActivity { component.inject(this); } - /** - * This must only be called from a DbThread - */ - boolean isDisabled(GroupId groupId, Contact c) throws DbException { + @Override + public boolean isDisabled(GroupId groupId, Contact c) throws DbException { return !forumSharingManager.canBeShared(groupId, c); } + + @Override + protected void share(GroupId g, ContactId c, String msg) + throws DbException { + forumSharingManager.sendInvitation(g, c, msg); + } + + @Override + protected int getSharingError() { + return R.string.forum_share_error; + } + + @Override + public int getMaximumMessageLength() { + return MAX_MESSAGE_BODY_LENGTH; + } } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java index 8414096f01073fbfbf44532af73030591cbe634f..a3faeb630de35101d606b194260be9aa3971c100 100644 --- a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java @@ -1,41 +1,20 @@ package org.briarproject.android.sharing; import android.os.Bundle; +import android.support.annotation.StringRes; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; import org.briarproject.R; import org.briarproject.android.ActivityComponent; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.db.DbException; -import org.briarproject.api.forum.ForumSharingManager; -import org.briarproject.api.sync.GroupId; -import java.util.Collection; -import java.util.logging.Logger; - -import javax.inject.Inject; - -import static android.widget.Toast.LENGTH_SHORT; -import static java.util.logging.Level.WARNING; - -public class ShareForumMessageFragment extends ShareMessageFragment { +public class ShareForumMessageFragment extends BaseMessageFragment { public final static String TAG = ShareForumMessageFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); - - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile ForumSharingManager forumSharingManager; - public static ShareForumMessageFragment newInstance(GroupId groupId, - Collection<ContactId> contacts) { - - ShareForumMessageFragment fragment = new ShareForumMessageFragment(); - fragment.setArguments(getArguments(groupId, contacts)); - return fragment; + public static ShareForumMessageFragment newInstance() { + return new ShareForumMessageFragment(); } @Override @@ -47,42 +26,25 @@ public class ShareForumMessageFragment extends ShareMessageFragment { } @Override - public void injectFragment(ActivityComponent component) { - component.inject(this); + @StringRes + protected int getButtonText() { + return R.string.forum_share_button; } @Override - public String getUniqueTag() { - return TAG; + @StringRes + protected int getHintText() { + return R.string.forum_share_message; } @Override - protected void share(final String msg) { - listener.runOnDbThread(new Runnable() { - @Override - public void run() { - try { - for (ContactId c : getContacts()) { - forumSharingManager. - sendInvitation(getGroupId(), c, msg); - } - } catch (DbException e) { - sharingError(); - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); + public void injectFragment(ActivityComponent component) { + component.inject(this); } @Override - protected void sharingError() { - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - int res = R.string.forum_share_error; - Toast.makeText(getContext(), res, LENGTH_SHORT).show(); - } - }); + public String getUniqueTag() { + return TAG; } + } diff --git a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java deleted file mode 100644 index ea79398cf0167b62722e3fdbad7417760fa6cc38..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.briarproject.android.sharing; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import org.briarproject.R; -import org.briarproject.android.fragment.BaseFragment; -import org.briarproject.android.view.LargeTextInputView; -import org.briarproject.android.view.TextInputView.TextInputListener; -import org.briarproject.api.blogs.BlogSharingManager; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.forum.ForumSharingManager; -import org.briarproject.api.sync.GroupId; -import org.briarproject.util.StringUtils; - -import java.util.ArrayList; -import java.util.Collection; - -import javax.inject.Inject; - -import static org.briarproject.android.sharing.ShareActivity.CONTACTS; -import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds; -import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; -import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; - -abstract class ShareMessageFragment extends BaseFragment - implements TextInputListener { - - protected ViewHolder ui; - private ShareActivity shareActivity; - - // Fields that are accessed from background threads must be volatile - @Inject - protected volatile ForumSharingManager forumSharingManager; - @Inject - protected volatile BlogSharingManager blogSharingManager; - private volatile GroupId groupId; - private volatile Collection<ContactId> contacts; - - protected static Bundle getArguments(GroupId groupId, - Collection<ContactId> contacts) { - - Bundle args = new Bundle(); - args.putByteArray(GROUP_ID, groupId.getBytes()); - args.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts)); - return args; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - shareActivity = (ShareActivity) context; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - // allow for "up" button to act as back button - setHasOptionsMenu(true); - - // get groupID and contactIDs from fragment arguments - groupId = new GroupId(getArguments().getByteArray(GROUP_ID)); - ArrayList<Integer> intContacts = - getArguments().getIntegerArrayList(CONTACTS); - if (intContacts == null) throw new IllegalArgumentException(); - contacts = ShareActivity.getContactsFromIntegers(intContacts); - - // inflate view - View v = inflater.inflate(R.layout.fragment_share_message, container, - false); - ui = new ViewHolder(v); - ui.message.setListener(this); - - return v; - } - - @Override - public void onStart() { - super.onStart(); - ui.message.showSoftKeyboard(); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - shareActivity.onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - protected void setTitle(int res) { - shareActivity.setTitle(res); - } - - @Override - public void onSendClick(String msg) { - // disable button to prevent accidental double invitations - ui.message.setSendButtonEnabled(false); - - msg = StringUtils.truncateUtf8(msg, MAX_INVITATION_MESSAGE_LENGTH); - share(msg); - - // don't wait for the invitation to be made before finishing activity - shareActivity.sharingSuccessful(ui.message); - } - - abstract void share(final String msg); - - abstract void sharingError(); - - protected Collection<ContactId> getContacts() { - return contacts; - } - - protected GroupId getGroupId() { - return groupId; - } - - protected static class ViewHolder { - protected final LargeTextInputView message; - - private ViewHolder(View v) { - message = (LargeTextInputView) v - .findViewById(R.id.invitationMessageView); - } - } -} diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java index 6a1ec4883dfcc6ea3c8563aef42f556741b41de0..a8eefd250f474069e20a40fb458af1013c43976f 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java @@ -253,6 +253,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI replyItem != null ? replyItem.getId() : null, handler); textInput.hideSoftKeyboard(); textInput.setVisibility(GONE); + textInput.setText(""); adapter.setReplyItem(null); } diff --git a/briar-android/src/org/briarproject/android/view/TextInputView.java b/briar-android/src/org/briarproject/android/view/TextInputView.java index dade999a0863fa0bf121e257b3e96cc550332cd5..ff75c84bfd064aaa22fb115e82fba23494e993be 100644 --- a/briar-android/src/org/briarproject/android/view/TextInputView.java +++ b/briar-android/src/org/briarproject/android/view/TextInputView.java @@ -101,7 +101,6 @@ public class TextInputView extends KeyboardAwareLinearLayout public void onClick(View v) { if (listener != null) { listener.onSendClick(ui.editText.getText().toString()); - ui.editText.setText(""); } } }); diff --git a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupConstants.java b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupConstants.java index 989844d0a72b0addbb4e3b8ba3f8a627b209dc68..def6c3f69bc660707c6ed088532dc7dab5908d29 100644 --- a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupConstants.java +++ b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupConstants.java @@ -19,4 +19,9 @@ public interface PrivateGroupConstants { */ int MAX_GROUP_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; + /** + * The maximum length of a group invitation message in bytes. + */ + int MAX_GROUP_INVITATION_MSG_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; + } diff --git a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java index 956a42344649b2d88cdbf0924d4c5ab1cda0986d..f2253c99a7c0c1999c1910146602e586ba4cf153 100644 --- a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java +++ b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java @@ -18,6 +18,9 @@ public interface PrivateGroupManager extends MessageTracker { @NotNull ClientId getClientId(); + /** Adds a new private group. */ + GroupId addPrivateGroup(String name) throws DbException; + /** Removes a dissolved private group. */ void removePrivateGroup(GroupId g) throws DbException; diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java index 6f40bd9c6c9c069c4e9de80d9cbfa7c887626b53..05c2d4021c4c766a2cdbcb89baea7e792a594aeb 100644 --- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java +++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.security.GeneralSecurityException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.logging.Logger; @@ -70,6 +71,21 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements return CLIENT_ID; } + @Override + public GroupId addPrivateGroup(String name) throws DbException { + PrivateGroup group; + Transaction txn = db.startTransaction(false); + try { + LocalAuthor a = identityManager.getLocalAuthor(txn); + group = privateGroupFactory.createPrivateGroup(name, a); + db.addGroup(txn, group.getGroup()); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + return group.getId(); + } + @Override public void removePrivateGroup(GroupId g) throws DbException { @@ -137,7 +153,24 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements @NotNull @Override public Collection<PrivateGroup> getPrivateGroups() throws DbException { - return Collections.emptyList(); + Collection<Group> groups; + Transaction txn = db.startTransaction(true); + try { + groups = db.getGroups(txn, getClientId()); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + try { + Collection<PrivateGroup> privateGroups = + new ArrayList<PrivateGroup>(groups.size()); + for (Group g : groups) { + privateGroups.add(privateGroupFactory.parsePrivateGroup(g)); + } + return privateGroups; + } catch (FormatException e) { + throw new DbException(e); + } } @Override