diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 9e4373be9..a034123a8 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" >
+
+
@@ -62,7 +66,7 @@
+ android:label="@string/app_name" >
+ android:label="@string/app_name" >
+ android:label="@string/app_name" >
From: %1$s
To: %1$s
New Message
- From:
- To:
+ From:
+ To:
(Anonymous)
Groups
New Group
Choose a name for your group:
New Post
Blogs
+ New Blog
+ Choose a name for your blog:
+ New Post
New nickname\u2026
Create an Identity
- Choose your nickname:
+ Choose your nickname:
Create
You don\'t have any contacts. Add a contact now?
Add
diff --git a/briar-android/src/net/sf/briar/android/groups/CreateBlogActivity.java b/briar-android/src/net/sf/briar/android/groups/CreateBlogActivity.java
new file mode 100644
index 000000000..46f6c9b8f
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/groups/CreateBlogActivity.java
@@ -0,0 +1,180 @@
+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.security.KeyPair;
+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.crypto.CryptoComponent;
+import net.sf.briar.api.crypto.CryptoExecutor;
+import net.sf.briar.api.db.DatabaseComponent;
+import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.messaging.GroupFactory;
+import net.sf.briar.api.messaging.LocalGroup;
+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 CreateBlogActivity extends BriarActivity
+implements OnEditorActionListener, OnClickListener {
+
+ private static final Logger LOG =
+ Logger.getLogger(CreateBlogActivity.class.getName());
+
+ private final BriarServiceConnection serviceConnection =
+ new BriarServiceConnection();
+
+ @Inject @CryptoExecutor private Executor cryptoExecutor;
+ 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 CryptoComponent crypto;
+ @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_blog_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 the blog in a background thread
+ cryptoExecutor.execute(new Runnable() {
+ public void run() {
+ KeyPair keyPair = crypto.generateSignatureKeyPair();
+ final byte[] publicKey = keyPair.getPublic().getEncoded();
+ final byte[] privateKey = keyPair.getPrivate().getEncoded();
+ LocalGroup g;
+ try {
+ g = groupFactory.createLocalGroup(name, publicKey,
+ privateKey);
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+ storeLocalGroup(g);
+ }
+ });
+ }
+
+ private void storeLocalGroup(final LocalGroup g) {
+ dbUiExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ serviceConnection.waitForStartup();
+ long now = System.currentTimeMillis();
+ db.addLocalGroup(g);
+ 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(InterruptedException e) {
+ if(LOG.isLoggable(INFO))
+ LOG.info("Interrupted while waiting for service");
+ Thread.currentThread().interrupt();
+ }
+ 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/CreateGroupActivity.java b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
index 0c150118b..e8c3ac199 100644
--- a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
@@ -123,6 +123,7 @@ implements OnEditorActionListener, OnClickListener {
dbUiExecutor.execute(new Runnable() {
public void run() {
try {
+ serviceConnection.waitForStartup();
Group g = groupFactory.createGroup(name);
long now = System.currentTimeMillis();
db.subscribe(g);
@@ -132,6 +133,10 @@ implements OnEditorActionListener, OnClickListener {
} catch(DbException e) {
if(LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
+ } catch(InterruptedException e) {
+ if(LOG.isLoggable(INFO))
+ LOG.info("Interrupted while waiting for service");
+ Thread.currentThread().interrupt();
} catch(IOException e) {
throw new RuntimeException(e);
}
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 f4d2cd873..8f5834084 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -215,11 +215,9 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
public void onClick(View view) {
if(view == newGroupButton) {
- if(restricted) {
- // FIXME: Hook this up to an activity
- } else {
- startActivity(new Intent(this, CreateGroupActivity.class));
- }
+ if(restricted)
+ startActivity(new Intent(this, CreateBlogActivity.class));
+ else startActivity(new Intent(this, CreateGroupActivity.class));
} else if(view == composeButton) {
if(noGroups) {
NoGroupsDialog dialog = new NoGroupsDialog();
@@ -294,11 +292,9 @@ implements OnClickListener, DatabaseListener, NoGroupsDialog.Listener {
}
public void createGroupButtonClicked() {
- if(restricted) {
- // FIXME: Hook this up to an activity
- } else {
- startActivity(new Intent(this, CreateGroupActivity.class));
- }
+ if(restricted)
+ startActivity(new Intent(this, CreateBlogActivity.class));
+ 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 193d1d557..b3c8e8023 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
@@ -87,6 +87,8 @@ implements OnItemSelectedListener, OnClickListener {
Intent i = getIntent();
restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
+ if(restricted) setTitle(R.string.compose_blog_title);
+ else setTitle(R.string.compose_group_title);
byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
if(b != null) groupId = new GroupId(b);
b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");