diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 9e4373be93c03bdd7329e04ec91425994f7c10bf..a034123a8cdda95581b0ecda3eff2d82fa1ff4fd 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" > </activity> + <activity + android:name=".android.groups.CreateBlogActivity" + android:label="@string/create_blog_title" > + </activity> <activity android:name=".android.groups.CreateGroupActivity" android:label="@string/create_group_title" > @@ -62,7 +66,7 @@ </activity> <activity android:name=".android.groups.WriteGroupMessageActivity" - android:label="@string/compose_group_title" > + android:label="@string/app_name" > </activity> <activity android:name=".android.identity.CreateIdentityActivity" @@ -74,7 +78,7 @@ </activity> <activity android:name=".android.messages.ConversationActivity" - android:label="@string/messages_title" > + android:label="@string/app_name" > </activity> <activity android:name=".android.messages.ConversationListActivity" @@ -82,7 +86,7 @@ </activity> <activity android:name=".android.messages.ReadPrivateMessageActivity" - android:label="@string/messages_title" > + android:label="@string/app_name" > </activity> <activity android:name=".android.messages.WritePrivateMessageActivity" diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 7577af4ffc87cb266f288144521bf6f1659f68ef..dbbb46c06527a277b59614c077211b6319bac7e9 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -43,17 +43,20 @@ <string name="format_from">From: %1$s</string> <string name="format_to">To: %1$s</string> <string name="compose_message_title">New Message</string> - <string name="from">From: </string> - <string name="to">To: </string> + <string name="from">From:</string> + <string name="to">To:</string> <string name="anonymous">(Anonymous)</string> <string name="groups_title">Groups</string> <string name="create_group_title">New Group</string> <string name="choose_group_name">Choose a name for your group:</string> <string name="compose_group_title">New Post</string> <string name="blogs_title">Blogs</string> + <string name="create_blog_title">New Blog</string> + <string name="choose_blog_name">Choose a name for your blog:</string> + <string name="compose_blog_title">New Post</string> <string name="create_nickname_item">New nickname\u2026</string> <string name="create_identity_title">Create an Identity</string> - <string name="choose_nickname">Choose your nickname: </string> + <string name="choose_nickname">Choose your nickname:</string> <string name="create_button">Create</string> <string name="no_contacts">You don\'t have any contacts. Add a contact now?</string> <string name="add_button">Add</string> 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 0000000000000000000000000000000000000000..46f6c9b8fe0d0743b6d826ff186cd97b390dd0cf --- /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 0c150118b6d8133a0807b2e0aa7a91bb01f3e6c4..e8c3ac199e68ebef099516017aba565ee3e61239 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 f4d2cd87323dd5cc4eda52101fcef52da9f0f6ab..8f58340846e7230102f5f017049afc723d6f000e 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 193d1d55799f62e5d2cb611f049d06e9cc22fc0f..b3c8e80230e8901776c355e09dcc0329f200efcd 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");