diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 711d5752b..9e4373be9 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -44,6 +44,10 @@
android:name=".android.contact.ContactListActivity"
android:label="@string/contact_list_title" >
+
+
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 9512c8e2d..7577af4ff 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -47,6 +47,8 @@
To:
(Anonymous)
Groups
+ New Group
+ Choose a name for your group:
New Post
Blogs
New nickname\u2026
diff --git a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
new file mode 100644
index 000000000..0c150118b
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
@@ -0,0 +1,154 @@
+package net.sf.briar.android.groups;
+
+import static android.text.InputType.TYPE_CLASS_TEXT;
+import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
+import static android.view.Gravity.CENTER;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
+import static android.widget.LinearLayout.VERTICAL;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
+import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import net.sf.briar.R;
+import net.sf.briar.android.BriarActivity;
+import net.sf.briar.android.BriarService;
+import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.api.android.DatabaseUiExecutor;
+import net.sf.briar.api.db.DatabaseComponent;
+import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.messaging.Group;
+import net.sf.briar.api.messaging.GroupFactory;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import com.google.inject.Inject;
+
+public class CreateGroupActivity extends BriarActivity
+implements OnEditorActionListener, OnClickListener {
+
+ private static final Logger LOG =
+ Logger.getLogger(CreateGroupActivity.class.getName());
+
+ private final BriarServiceConnection serviceConnection =
+ new BriarServiceConnection();
+
+ private EditText nameEntry = null;
+ private Button createButton = null;
+ private ProgressBar progress = null;
+
+ // Fields that are accessed from background threads must be volatile
+ @Inject private volatile GroupFactory groupFactory;
+ @Inject private volatile DatabaseComponent db;
+ @Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(null);
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(MATCH_MATCH);
+ layout.setOrientation(VERTICAL);
+ layout.setGravity(CENTER_HORIZONTAL);
+
+ TextView chooseNickname = new TextView(this);
+ chooseNickname.setGravity(CENTER);
+ chooseNickname.setTextSize(18);
+ chooseNickname.setPadding(10, 10, 10, 10);
+ chooseNickname.setText(R.string.choose_group_name);
+ layout.addView(chooseNickname);
+
+ nameEntry = new EditText(this);
+ nameEntry.setTextSize(18);
+ nameEntry.setMaxLines(1);
+ nameEntry.setPadding(10, 10, 10, 10);
+ int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES;
+ nameEntry.setInputType(inputType);
+ nameEntry.setOnEditorActionListener(this);
+ layout.addView(nameEntry);
+
+ createButton = new Button(this);
+ createButton.setLayoutParams(WRAP_WRAP);
+ createButton.setText(R.string.create_button);
+ createButton.setOnClickListener(this);
+ layout.addView(createButton);
+
+ progress = new ProgressBar(this);
+ progress.setLayoutParams(WRAP_WRAP);
+ progress.setIndeterminate(true);
+ progress.setVisibility(GONE);
+ layout.addView(progress);
+
+ setContentView(layout);
+
+ // Bind to the service so we can wait for it to start
+ bindService(new Intent(BriarService.class.getName()),
+ serviceConnection, 0);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unbindService(serviceConnection);
+ }
+
+ public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
+ validateName();
+ return true;
+ }
+
+ public void onClick(View view) {
+ if(!validateName()) return;
+ final String name = nameEntry.getText().toString();
+ // Replace the button with a progress bar
+ createButton.setVisibility(GONE);
+ progress.setVisibility(VISIBLE);
+ // Create and store the group in a background thread
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ Group g = groupFactory.createGroup(name);
+ long now = System.currentTimeMillis();
+ db.subscribe(g);
+ long duration = System.currentTimeMillis() - now;
+ if(LOG.isLoggable(INFO))
+ LOG.info("Storing group took " + duration + " ms");
+ } catch(DbException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+ runOnUiThread(new Runnable() {
+ public void run() {
+ finish();
+ }
+ });
+ }
+ });
+ }
+
+ private boolean validateName() {
+ if(nameEntry.getText().toString().equals("")) return false;
+ // Hide the soft keyboard
+ Object o = getSystemService(INPUT_METHOD_SERVICE);
+ ((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
+ return true;
+ }
+}
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
index 45d08d452..f4d2cd873 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -215,7 +215,11 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
public void onClick(View view) {
if(view == newGroupButton) {
- // FIXME: Hook this button up to an activity
+ if(restricted) {
+ // FIXME: Hook this up to an activity
+ } else {
+ startActivity(new Intent(this, CreateGroupActivity.class));
+ }
} else if(view == composeButton) {
if(noGroups) {
NoGroupsDialog dialog = new NoGroupsDialog();
@@ -290,7 +294,11 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
}
public void createGroupButtonClicked() {
- // FIXME: Hook this button up to an activity
+ if(restricted) {
+ // FIXME: Hook this up to an activity
+ } else {
+ startActivity(new Intent(this, CreateGroupActivity.class));
+ }
}
public void cancelButtonClicked() {
diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
index 4f7f2ff08..193d1d557 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
@@ -7,8 +7,8 @@ import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.LocalAuthorItem.ANONYMOUS;
-import static net.sf.briar.android.LocalAuthorItem.NEW;
+import static net.sf.briar.android.identity.LocalAuthorItem.ANONYMOUS;
+import static net.sf.briar.android.identity.LocalAuthorItem.NEW;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import java.io.IOException;
@@ -25,10 +25,10 @@ import net.sf.briar.R;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
-import net.sf.briar.android.LocalAuthorItem;
-import net.sf.briar.android.LocalAuthorItemComparator;
-import net.sf.briar.android.LocalAuthorSpinnerAdapter;
import net.sf.briar.android.identity.CreateIdentityActivity;
+import net.sf.briar.android.identity.LocalAuthorItem;
+import net.sf.briar.android.identity.LocalAuthorItemComparator;
+import net.sf.briar.android.identity.LocalAuthorSpinnerAdapter;
import net.sf.briar.android.widgets.HorizontalSpace;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
diff --git a/briar-android/src/net/sf/briar/android/LocalAuthorItem.java b/briar-android/src/net/sf/briar/android/identity/LocalAuthorItem.java
similarity index 91%
rename from briar-android/src/net/sf/briar/android/LocalAuthorItem.java
rename to briar-android/src/net/sf/briar/android/identity/LocalAuthorItem.java
index 0e2d63c09..f867d246c 100644
--- a/briar-android/src/net/sf/briar/android/LocalAuthorItem.java
+++ b/briar-android/src/net/sf/briar/android/identity/LocalAuthorItem.java
@@ -1,4 +1,4 @@
-package net.sf.briar.android;
+package net.sf.briar.android.identity;
import net.sf.briar.api.LocalAuthor;
diff --git a/briar-android/src/net/sf/briar/android/LocalAuthorItemComparator.java b/briar-android/src/net/sf/briar/android/identity/LocalAuthorItemComparator.java
similarity index 75%
rename from briar-android/src/net/sf/briar/android/LocalAuthorItemComparator.java
rename to briar-android/src/net/sf/briar/android/identity/LocalAuthorItemComparator.java
index c9ce0a1b0..9d75dc118 100644
--- a/briar-android/src/net/sf/briar/android/LocalAuthorItemComparator.java
+++ b/briar-android/src/net/sf/briar/android/identity/LocalAuthorItemComparator.java
@@ -1,7 +1,7 @@
-package net.sf.briar.android;
+package net.sf.briar.android.identity;
-import static net.sf.briar.android.LocalAuthorItem.ANONYMOUS;
-import static net.sf.briar.android.LocalAuthorItem.NEW;
+import static net.sf.briar.android.identity.LocalAuthorItem.ANONYMOUS;
+import static net.sf.briar.android.identity.LocalAuthorItem.NEW;
import java.util.Comparator;
diff --git a/briar-android/src/net/sf/briar/android/LocalAuthorSpinnerAdapter.java b/briar-android/src/net/sf/briar/android/identity/LocalAuthorSpinnerAdapter.java
similarity index 92%
rename from briar-android/src/net/sf/briar/android/LocalAuthorSpinnerAdapter.java
rename to briar-android/src/net/sf/briar/android/identity/LocalAuthorSpinnerAdapter.java
index b112a4056..493653d4d 100644
--- a/briar-android/src/net/sf/briar/android/LocalAuthorSpinnerAdapter.java
+++ b/briar-android/src/net/sf/briar/android/identity/LocalAuthorSpinnerAdapter.java
@@ -1,7 +1,7 @@
-package net.sf.briar.android;
+package net.sf.briar.android.identity;
-import static net.sf.briar.android.LocalAuthorItem.ANONYMOUS;
-import static net.sf.briar.android.LocalAuthorItem.NEW;
+import static net.sf.briar.android.identity.LocalAuthorItem.ANONYMOUS;
+import static net.sf.briar.android.identity.LocalAuthorItem.NEW;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
index e07efb08f..7b5ec9f72 100644
--- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
+++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java
@@ -10,9 +10,9 @@ import java.util.logging.Logger;
import net.sf.briar.android.BriarActivity;
import net.sf.briar.android.BriarService;
import net.sf.briar.android.BriarService.BriarServiceConnection;
-import net.sf.briar.android.LocalAuthorItem;
-import net.sf.briar.android.LocalAuthorItemComparator;
-import net.sf.briar.android.LocalAuthorSpinnerAdapter;
+import net.sf.briar.android.identity.LocalAuthorItem;
+import net.sf.briar.android.identity.LocalAuthorItemComparator;
+import net.sf.briar.android.identity.LocalAuthorSpinnerAdapter;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.LocalAuthor;
import net.sf.briar.api.android.BundleEncrypter;
diff --git a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
index ddd2ac6d6..39698b0e1 100644
--- a/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
+++ b/briar-android/src/net/sf/briar/android/invitation/NetworkSetupView.java
@@ -1,13 +1,13 @@
package net.sf.briar.android.invitation;
import static android.view.Gravity.CENTER;
-import static net.sf.briar.android.LocalAuthorItem.NEW;
+import static net.sf.briar.android.identity.LocalAuthorItem.NEW;
import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP;
import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
import net.sf.briar.R;
-import net.sf.briar.android.LocalAuthorItem;
-import net.sf.briar.android.LocalAuthorSpinnerAdapter;
import net.sf.briar.android.identity.CreateIdentityActivity;
+import net.sf.briar.android.identity.LocalAuthorItem;
+import net.sf.briar.android.identity.LocalAuthorSpinnerAdapter;
import net.sf.briar.api.AuthorId;
import android.content.Context;
import android.content.Intent;