diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 6b12578c8..5dbdd9771 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -52,5 +52,9 @@
android:name=".android.messages.ReadMessageActivity"
android:label="@string/messages_title" >
+
+
diff --git a/briar-android/res/drawable-hdpi/social_send_now.png b/briar-android/res/drawable-hdpi/social_send_now.png
new file mode 100644
index 000000000..6bdd9585f
Binary files /dev/null and b/briar-android/res/drawable-hdpi/social_send_now.png differ
diff --git a/briar-android/res/drawable-mdpi/social_send_now.png b/briar-android/res/drawable-mdpi/social_send_now.png
new file mode 100644
index 000000000..515668a6b
Binary files /dev/null and b/briar-android/res/drawable-mdpi/social_send_now.png differ
diff --git a/briar-android/res/drawable-xhdpi/social_send_now.png b/briar-android/res/drawable-xhdpi/social_send_now.png
new file mode 100644
index 000000000..0c870d2ce
Binary files /dev/null and b/briar-android/res/drawable-xhdpi/social_send_now.png differ
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index df481efc4..df2deb07c 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -43,4 +43,5 @@
Done
Messages
New Message
+ New Message
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
index c28abac25..f178060fd 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
@@ -165,13 +165,17 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
}
public void onClick(View view) {
- // FIXME: Hook this button up to an activity
+ Intent i = new Intent(this, WriteMessageActivity.class);
+ i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
+ i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
+ startActivity(i);
}
public void onItemClick(AdapterView> parent, View view, int position,
long id) {
PrivateMessageHeader item = adapter.getItem(position);
Intent i = new Intent(this, ReadMessageActivity.class);
+ i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
i.putExtra("net.sf.briar.MESSAGE_ID", item.getId().getBytes());
i.putExtra("net.sf.briar.CONTENT_TYPE", item.getContentType());
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationItem.java b/briar-android/src/net/sf/briar/android/messages/ConversationItem.java
deleted file mode 100644
index 2640bc105..000000000
--- a/briar-android/src/net/sf/briar/android/messages/ConversationItem.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.sf.briar.android.messages;
-
-import net.sf.briar.api.db.PrivateMessageHeader;
-import net.sf.briar.api.messaging.MessageId;
-
-class ConversationItem {
-
- private final PrivateMessageHeader header;
- private final byte[] body;
- private final boolean expanded;
-
- ConversationItem(PrivateMessageHeader header) {
- this.header = header;
- body = null;
- expanded = false;
- }
-
- // Collapse an existing item
- ConversationItem(ConversationItem item) {
- this.header = item.header;
- body = null;
- expanded = false;
- }
-
- // Expand an existing item
- ConversationItem(ConversationItem item, byte[] body) {
- this.header = item.header;
- this.body = body;
- expanded = true;
- }
-
- MessageId getId() {
- return header.getId();
- }
-
- String getContentType() {
- return header.getContentType();
- }
-
- String getSubject() {
- return header.getSubject();
- }
-
- long getTimestamp() {
- return header.getTimestamp();
- }
-
- boolean isRead() {
- return header.isRead();
- }
-
- boolean isStarred() {
- return header.isStarred();
- }
-
- boolean isIncoming() {
- return header.isIncoming();
- }
-
- byte[] getBody() {
- return body;
- }
-
- boolean isExpanded() {
- return expanded;
- }
-}
diff --git a/briar-android/src/net/sf/briar/android/messages/ReadMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/ReadMessageActivity.java
index 9a2ec2b49..e99824975 100644
--- a/briar-android/src/net/sf/briar/android/messages/ReadMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ReadMessageActivity.java
@@ -18,6 +18,7 @@ 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.ContactId;
import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DatabaseExecutor;
import net.sf.briar.api.db.DbException;
@@ -47,6 +48,8 @@ implements OnClickListener {
@Inject private DatabaseComponent db;
@Inject @DatabaseExecutor private Executor dbExecutor;
+ private ContactId contactId = null;
+ private String contactName = null;
private MessageId messageId = null;
private boolean starred = false;
private ImageButton starButton = null, replyButton = null;
@@ -57,12 +60,15 @@ implements OnClickListener {
super.onCreate(null);
Intent i = getIntent();
- String contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
+ int cid = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
+ if(cid == -1) throw new IllegalStateException();
+ contactId = new ContactId(cid);
+ contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
if(contactName == null) throw new IllegalStateException();
setTitle(contactName);
- byte[] id = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
- if(id == null) throw new IllegalStateException();
- messageId = new MessageId(id);
+ byte[] mid = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
+ if(mid == null) throw new IllegalStateException();
+ messageId = new MessageId(mid);
String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
if(contentType == null) throw new IllegalStateException();
long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
@@ -181,7 +187,6 @@ implements OnClickListener {
unbindService(serviceConnection);
}
- @Override
public void onClick(View view) {
if(view == starButton) {
final MessageId id = messageId;
@@ -201,7 +206,11 @@ implements OnClickListener {
starButton.setImageResource(R.drawable.rating_important);
else starButton.setImageResource(R.drawable.rating_not_important);
} else if(view == replyButton) {
- // FIXME: Hook this up to an activity
+ Intent i = new Intent(this, WriteMessageActivity.class);
+ i.putExtra("net.sf.briar.CONTACT_ID", contactId.getInt());
+ i.putExtra("net.sf.briar.CONTACT_NAME", contactName);
+ i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
+ startActivity(i);
}
}
}
diff --git a/briar-android/src/net/sf/briar/android/messages/WriteMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/WriteMessageActivity.java
new file mode 100644
index 000000000..92d0dbfdf
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/WriteMessageActivity.java
@@ -0,0 +1,164 @@
+package net.sf.briar.android.messages;
+
+import static android.view.Gravity.CENTER_VERTICAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+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 java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+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.ContactId;
+import net.sf.briar.api.android.BundleEncrypter;
+import net.sf.briar.api.db.DatabaseComponent;
+import net.sf.briar.api.db.DatabaseExecutor;
+import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.messaging.Message;
+import net.sf.briar.api.messaging.MessageFactory;
+import net.sf.briar.api.messaging.MessageId;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.ScrollView;
+
+import com.google.inject.Inject;
+
+public class WriteMessageActivity extends BriarActivity
+implements OnClickListener {
+
+ private static final Logger LOG =
+ Logger.getLogger(WriteMessageActivity.class.getName());
+
+ private final BriarServiceConnection serviceConnection =
+ new BriarServiceConnection();
+
+ @Inject private BundleEncrypter bundleEncrypter;
+ @Inject private DatabaseComponent db;
+ @Inject @DatabaseExecutor private Executor dbExecutor;
+ @Inject private MessageFactory messageFactory;
+
+ private ContactId contactId = null;
+ private String contactName = null;
+ private MessageId parentId = null;
+ private ImageButton cancelButton = null, sendButton = null;
+ private EditText content = null;
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(null);
+
+ Intent i = getIntent();
+ int cid = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
+ if(cid == -1) throw new IllegalStateException();
+ contactId = new ContactId(cid);
+ contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
+ if(contactName == null) throw new IllegalStateException();
+ byte[] pid = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
+ if(pid != null) parentId = new MessageId(pid);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ layout.setOrientation(VERTICAL);
+
+ LinearLayout header = new LinearLayout(this);
+ header.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+ header.setOrientation(HORIZONTAL);
+ header.setGravity(CENTER_VERTICAL);
+
+ cancelButton = new ImageButton(this);
+ cancelButton.setPadding(5, 5, 5, 5);
+ cancelButton.setBackgroundResource(0);
+ cancelButton.setImageResource(R.drawable.navigation_cancel);
+ cancelButton.setOnClickListener(this);
+ header.addView(cancelButton);
+
+ sendButton = new ImageButton(this);
+ sendButton.setPadding(5, 5, 5, 5);
+ sendButton.setBackgroundResource(0);
+ sendButton.setImageResource(R.drawable.social_send_now);
+ sendButton.setOnClickListener(this);
+ header.addView(sendButton);
+ layout.addView(header);
+
+ ScrollView scrollView = new ScrollView(this);
+ content = new EditText(this);
+ content.setPadding(10, 10, 10, 10);
+ if(state != null && bundleEncrypter.decrypt(state)) {
+ Parcelable p = state.getParcelable("net.sf.briar.CONTENT");
+ if(p != null) content.onRestoreInstanceState(p);
+ }
+ scrollView.addView(content);
+ layout.addView(scrollView);
+
+ setContentView(layout);
+
+ // Bind to the service so we can wait for the DB to be opened
+ bindService(new Intent(BriarService.class.getName()),
+ serviceConnection, 0);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle state) {
+ Parcelable p = content.onSaveInstanceState();
+ state.putParcelable("net.sf.briar.CONTENT", p);
+ bundleEncrypter.encrypt(state);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unbindService(serviceConnection);
+ }
+
+ public void onClick(View view) {
+ if(view == cancelButton) {
+ finish();
+ } else if(view == sendButton) {
+ final Message m;
+ try {
+ byte[] body = content.getText().toString().getBytes("UTF-8");
+ m = messageFactory.createPrivateMessage(parentId,
+ "text/plain", body);
+ } catch(UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ } catch(GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+ final ContactId contactId = this.contactId;
+ dbExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ serviceConnection.waitForStartup();
+ db.addLocalPrivateMessage(m, contactId);
+ } 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();
+ }
+ }
+ });
+ finish();
+ }
+ }
+}