From f549b6d818f2f5cfb3c65c8acf847a9df848a391 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Tue, 5 Mar 2013 01:57:15 +0000
Subject: [PATCH] Android UI for writing private messages (text only for now).

---
 briar-android/AndroidManifest.xml             |   4 +
 .../res/drawable-hdpi/social_send_now.png     | Bin 0 -> 1432 bytes
 .../res/drawable-mdpi/social_send_now.png     | Bin 0 -> 1292 bytes
 .../res/drawable-xhdpi/social_send_now.png    | Bin 0 -> 1691 bytes
 briar-android/res/values/strings.xml          |   1 +
 .../messages/ConversationActivity.java        |   6 +-
 .../android/messages/ConversationItem.java    |  67 -------
 .../android/messages/ReadMessageActivity.java |  21 ++-
 .../messages/WriteMessageActivity.java        | 164 ++++++++++++++++++
 9 files changed, 189 insertions(+), 74 deletions(-)
 create mode 100644 briar-android/res/drawable-hdpi/social_send_now.png
 create mode 100644 briar-android/res/drawable-mdpi/social_send_now.png
 create mode 100644 briar-android/res/drawable-xhdpi/social_send_now.png
 delete mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationItem.java
 create mode 100644 briar-android/src/net/sf/briar/android/messages/WriteMessageActivity.java

diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 6b12578c8c..5dbdd97713 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" >
 		</activity>
+		<activity
+			android:name=".android.messages.WriteMessageActivity"
+			android:label="@string/compose_title" >
+		</activity>
 	</application>
 </manifest>
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 0000000000000000000000000000000000000000..6bdd9585fcfe188ec4a81c81b2861f2be0883499
GIT binary patch
literal 1432
zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y
zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP
zs8ErclUHn2VXFi-*9yo63F|8<fR&VF+bTgE72zA8;GAESs$i;Tpqp%9W~g9hqGxDg
zU}<8hqhMrUXrOOsq;FuZYiM9)YHnp<r~m~@K--E^(yW49+@N*=dA3R!B_#z``ugSN
z<$C4Ddih1^`i7R4mih)p`bI{&Koz>hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83
zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s0<RzFwUtj!6b93RUi%Wu15$?rmaB)aw
zL8^XGYH@yPQ8F;%(v(3~6<9eJr6!i-7lq{K=fFZSAS1sdzc?emK*2fKRL@YsH!(Rg
z4<rKC;p=PVnO9trn3tUD>0+w{G(#^lGsVi((#^=w*wE3`$-u?X(ACh=#L&{!#L3yw
z&D7A`#K{n**Cju>G&eP`1g19yq1OqgUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZns$A
zG!Lpb1-Dx)aq86vIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1zw&OYcfq{XE%hSa%
zq~g|_ncm*ah9a%$w;n}j#cHlq`f=;Up(vKSyGowRf5`u_Ic8UYxDrRu8n41Y(V9ix
zj=7?_k2&WYG6<Qw<Z@*KQ@g|DvUBD;&5Mn<whDyJi9Xa-Y0SWOfI)(R`NMw3pg46g
zu2$2M)E8<T$w!ke#xrcu%#gj+{%yhT9jzBwuQ0E5ntg%IL~OQzQ+30t32XlC;@HF@
z+qzRpi(&f(>+pq)S7Q{?FX)v>hBl<X;GCt>@RTXC@lycjElw^MRtJNgw1xiHBbrw$
z7iUREad4?DwfO(9|KkD25XN<qMrPqEB?6%gGnv;1NUf@#@t$p>Ws%>6A_<243(6*M
z1Q&>Q#PnJ+ZQ)(Sr7(lN+eB4np-Rl>I_8aknLIOVmNUf`zJBv8*7w8qIklG<Z?5{z
z>caj&!fK&o=9Yc~<~P-xYQG)((k-Sve4csS%hK^#W%IU$mlvFR={My`nR>Xw`Bhsa
zojl_LOj~BT?f#jd!z$`ztfRh4cT&WKo(~1>w~f|uE9lQjzEhXk)~0`~l=0WXz@zC7
z#{MZMYJa50h$pn{_I19vBW9!XJZY`OX+pwx*s{BhDF>f<x+p1z-9atkTl*8<J3IIe
z2ox`PXQWp?Rs5%#$}9I%h4b25PycX?;rkkS&Gf5=#C66QX+7?*j!xrh=y|KFy&$}M
pUb)z3{iTcs&^QuE`Yo2g;QN0~`j-n8Gl4}VgQu&X%Q~loCII7I_(cE!

literal 0
HcmV?d00001

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 0000000000000000000000000000000000000000..515668a6b6c37f0c93f737def79a203e083b7d61
GIT binary patch
literal 1292
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y
zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP
zs8ErclUHn2VXFi-*9yo63F|8<fR&VF+bTgE72zA8;GAESs$i;Tpqp%9W~g9hqGxDg
zU}<8hqhMrUXrOOsq;FuZYiM9)YHnp<r~m~@K--E^(yW49+@N*=dA3R!B_#z``ugSN
z<$C4Ddih1^`i7R4mih)p`bI{&Koz>hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83
zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s0<RzFwUtj!6b93RUi%Wu15$?rmaB)aw
zL8^XGYH@yPQ8F;%(v(3~6<9eJr6!i-7lq{K=fFZSAS1sdzc?emK*2fKRL@YsH!(Rg
z4<rKC;p=PVnO9trn3tUD>0+w{G(#^lGsVi((#^=w*wEF~$-u?X(ACh=#L&{!#L3yw
z&D7A`#K{n**Cju>G&eP`1g19yq}S2N)z!e*8K+)QV#qB3+U$~Alv$RV;#QQOs{r=2
zRVHq?;5HAcHwBwpApUT{=@xyUWAs5$ixkx`Az=CeG2sap$bl#Q)I4B%F9Id(b=LP7
z7#Qn3T^vIyZoQd)+Uu}`h=a7W>y{?2*be^>8^xRQmNaqIHR;8^xWq5;rTR#Iz{RN=
zY%y9vANLA4hA;X$v4ZWL(v)YZYA+A*$VeGYzBhTN`Sz6$cjYadxp?V?Clk4!FfF^^
zk{bEA#-d=U@`T*m8_N@zrX^aPoy+y>5xd4=tDFNNQc7tZ2Y5>kORSg@@=&1fp>=L!
z_>NZ36(@HF3Pv{A$|^ZVuj2Z^w`cD!VY>v0YYD<>PI)R9lPmc1d9RrYt#sI(*C@X5
zh4FjQ$X4AM-O57SO11X)2eqWdTJ2d`l#(mI=77zc!xK6FMLP7#S~QrwXb~zov2l_2
zxv5Wfybz3>l70SxW~R28QSQ-s8(B7g5S_&2{_ftCM^`5?ncnAruk^q?q$=t$OP|&S
z?LRCmVVQfT#msl%l?hD<;94stU=iqU;#_qkAogP>w~Xrocc~uj#@;pcJ!}as*XA5v
zSG9gZ*7+xfAx!5t@GjrQ>@K*Yg*$eA%D%h0|I?>%|EX?_XJlh=Nli=>>t9d<DxW-E
L{an^LB{Ts5+LOX~

literal 0
HcmV?d00001

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 0000000000000000000000000000000000000000..0c870d2ce19d9c4469dccaaeee0d1d635232803f
GIT binary patch
literal 1691
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m{l@EB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+*
zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn
zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9<K~
zz|zE0N5ROz&_LhNNZ-I**U-Sq)ZEIzPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj
z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5
zFD<cE0=g99h1>$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;Np<V
zf>iyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh**NZ(?$0
z9!LbN!`Ii!Gq1QLF)umQ)5TT^Xog;9W{Q=mrJIqVv7wo%lYxt&p{t>#iJ_&diIcOV
zo2j9>iIX8ruS<S%X>Mv>2~2MaLa#Yay`aR9TL84#CABECEH%ZgC_h&L>}jh^+-@<!
zX&zK>3U0TU;?%1Tbc{YIYLTKECIn1BASOKF0y*%cpPC0u??u3beK7s_31EKV^>lFz
zskrrKmVdTzpvckB>o;B%>R#){>&Uv$+MG>9L@=g<BQNHK-~Q$ug%7`fROYz0>dODc
zkAgJBRz|t54&8FAY}UsZ3ub2zpHD^3&z62a*xxw)oXPt;pWp3%@4G2bBz0TS=~)bF
z4V(!~Gf=3KTUlFg3C8SeK5D|N#?iFyy{5&#^@|gv?y#Lds2?vop?J@G-Wg2c2Tcpu
zdVXm%tY#LI{90HrVGf(|BbWIy4_`IRf3W$9zy`l>zh7{KvwO6N&tP}@)~fQdWA_8o
zA7(jBIZfqz>eoKpTpD*&F#Lc}1<$*Smd=U|Tl^oeYcy3&KA-G9<)CW;*O?~ugqz=G
zCOlNw*Hklm|80i)gDg8()-`i4c(R)z>G@Q>7?sP<_-{D7-(h)vaLIZmkKY##{kvze
z=)&W_pM9D($&^J0n_DF*ST0)dpkYGih0^e?j!EuwSk@n?y(YC%EMaDd%rYl!_bD@_
z{R)28FxV{%ZJ409LaT214Z+(7Eem*Tk^`5%>zH%MSWKiP=h`cuX_I8mH%UJ*;$Cyb
zLg5^9(*0Z!6TgnHM;snyU%7C7<>^CpmQKzLHzn^qdY0bg)YD+t75J#M=VTDqa@jZC
zu9@l)#_lrLPYAA4cbe<BJ|}6zViC3D8D97Ex;9PrxNjF%{_)-m`}6vnWa>GeH7U%H
zcj5E!KFy!SHDyPN>T-vkXCfYT&ux_LFTWPKAh6&RlUnBQG*11S+h6TS60O`eVU<cm
zqD$ECl-#Qw-<=zrJA)P9O1auTy2T_i<<x@|>BJ-9zXS_&8Pz)57%JUrI%hA8ls9u0
zwNno2_#w{sOVfYWo*R7f&x*ERb3StPUcV8umC4lthjqt0_`gipBF^ZgQ{yyWX`N<+
z%6`pvEPFe5EMutN+4%GBvIfah;>t!Fn04R8Klxgl))C*^yP4@uj!>bc;w)zVo%Q~u
z#i9;E2{T{U8$G(WSFT)iftR>PQ}yfMBU@Q!q-}ln*FPnOwSw_oO3*iD&FN|OlZ_dD
m7=#b77$8vz-rMS#co@E`>cm&CeD46NE<9cRT-G@yGywn*w0tT6

literal 0
HcmV?d00001

diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index df481efc4d..df2deb07c7 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -43,4 +43,5 @@
 	<string name="done_button">Done</string>
 	<string name="messages_title">Messages</string>
 	<string name="compose_button">New Message</string>
+	<string name="compose_title">New Message</string>
 </resources>
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 c28abac256..f178060fda 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 2640bc105e..0000000000
--- 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 9a2ec2b492..e998249754 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 0000000000..92d0dbfdff
--- /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();
+		}
+	}
+}
-- 
GitLab