From 1ce1cf6f631612cc089f19fec9493ee8bd127860 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Fri, 1 Mar 2013 20:59:53 +0000
Subject: [PATCH] Added conversation list screen, minor tweaks to contact list
 screen.

---
 briar-android/AndroidManifest.xml             |   4 +
 .../res/drawable-hdpi/rating_important.png    | Bin 0 -> 1704 bytes
 .../drawable-hdpi/rating_not_important.png    | Bin 0 -> 1839 bytes
 .../res/drawable-mdpi/rating_important.png    | Bin 0 -> 1434 bytes
 .../drawable-mdpi/rating_not_important.png    | Bin 0 -> 1463 bytes
 .../res/drawable-xhdpi/content_new_email.png  | Bin 0 -> 1703 bytes
 .../res/drawable-xhdpi/rating_important.png   | Bin 0 -> 2045 bytes
 .../drawable-xhdpi/rating_not_important.png   | Bin 0 -> 2340 bytes
 briar-android/res/values/strings.xml          |   5 +-
 .../sf/briar/android/HomeScreenActivity.java  |   4 +-
 .../android/contact/ContactListActivity.java  |  21 +-
 .../android/contact/ContactListAdapter.java   |  12 +-
 .../android/contact/ContactListItem.java      |   3 +-
 .../messages/ConversationListActivity.java    | 225 ++++++++++++++++++
 .../messages/ConversationListAdapter.java     |  75 ++++++
 .../messages/ConversationListItem.java        |  81 +++++++
 16 files changed, 408 insertions(+), 22 deletions(-)
 create mode 100644 briar-android/res/drawable-hdpi/rating_important.png
 create mode 100644 briar-android/res/drawable-hdpi/rating_not_important.png
 create mode 100644 briar-android/res/drawable-mdpi/rating_important.png
 create mode 100644 briar-android/res/drawable-mdpi/rating_not_important.png
 create mode 100644 briar-android/res/drawable-xhdpi/content_new_email.png
 create mode 100644 briar-android/res/drawable-xhdpi/rating_important.png
 create mode 100644 briar-android/res/drawable-xhdpi/rating_not_important.png
 create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
 create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
 create mode 100644 briar-android/src/net/sf/briar/android/messages/ConversationListItem.java

diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 44027595bf..8dcdb7163d 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -40,5 +40,9 @@
 			android:name=".android.invitation.AddContactActivity"
 			android:label="@string/add_contact_title" >
 		</activity>
+		<activity
+			android:name=".android.messages.ConversationListActivity"
+			android:label="@string/messages_title" >
+		</activity>
 	</application>
 </manifest>
diff --git a/briar-android/res/drawable-hdpi/rating_important.png b/briar-android/res/drawable-hdpi/rating_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c25f351188f98caa89792889ae3e27960c16da7
GIT binary patch
literal 1704
zcmaJ?Yfuwc6i$H1qeTS)ff2inh{8a2HwHptBIW@SaS?%mR742L0x8*S%q|dgP{68F
zP)AWwunJW~TNreTS}X#=N(4c~Hx(_6wW7rbB2^xa?FNDNN9oS&-h0oS?>pal+}W=q
z!dKYax!cibG<#X7G?H2&^J_DM`o>y}?4TAmGFVPV;mKsCLXXl!Dm)1VWSAlajYJiy
ztPQQGfJU?QR7cB6IkJkc#4(n_?87o(Itopr34#ndg)$8#fh06Vtrap~)ip8!wMxj0
z^+zB?CqYxyp&RvR)W+~=<;FB6PsI#c1_%s%iU31N1z^B5T7qv7GRJxO)ZT0cnZURU
znI>d@6eUL@012)~0e=?cr-TAvAb`VyIS`M-^99%t41q8kgt&e%#P{d&AsCo=m{c^q
zDw!WC4Vj2VorKI(lGO1*Ff%igmAQn4>r+6O$K!zz8)UQnC=Wj(OG_#Yep+I|B!d(s
zlzO#}RO4E}%&17h(@7zdQu;9kOgBZVB__&56$~^ebRf)v%qdMeBFO){V%U^7K}Mqg
z=>1P(B05Wlf{`eJr|Xqe<B}JcL+SVuJ*psaeKd}1CaV~cijz2zit7MLls^jw5QS2$
zHCx6J2*Q_X2~wd|qB5zFNpY~$Y89WeBp8;60|WiVkQ9c4VIBwO1#`p_QHVdx<%r=)
ztQ1$KW2ly##H#+m@}|X_hXK=3k)^0!oq?)C^f(5LC(Tz+uO(nwz6q>qdM(^(u^=S|
zG`IF&t)4Vd^JCsl4K8(<8hunt&AXl&Y{N0{9_qfh%cP=c!~N$a*V5*QTun72koxfc
zN8fGk3_%#6u>5u9+cN9seFlfi$G7Z`$X_JP8Y;87FL9{v+9y}u*lJx60p=&}b&rEv
zwWgHbFI<ZrY6_2d)a;qNS(C{g>lk}}@y)s0j^gq{&9mrBm}jCVa15<yoLh^W{7b#Q
zv0pDgeQ(!WBU;$v<df&)?X|{e5g6)H=(T(_-pb<#*VwoXwt)<vGQ`I>Y-i5GJ(hWo
z<wZ919Y#T_4~i5ai$q3VMAFN;yNX}7Dds{mJD^wfUTxtu9i4Wk*xNLvJ(`M$bUCAZ
z)4Wq*{O&v6iMwy1m0?F*`rDh&7k@IlSn<$yrpZ=2Yh}B-RdzT1r(wq`VvZ&^=rOm;
za_s%4Qtv*4*Vdy}EnKpQ$lO~?PmzUONbU+<nm90O|HMrvc6h#+-hJ8m?25+(ZtR2T
zK}OHomXYol7te1m%IdD<MA0qRdOR(1TwU~T-^HtA0z-3`cvJ7(TI+_~{*`Aolnku9
zGpsr-u)03#VL6x^uPb<VJG|KcN5t*@XxUc75vH~#EN**V5Y4@pK0G_!{lLr^gRifv
zO@r}#%%!|nDIUWXMNNw!7v+Fbqb$b0jBm*>#-C~0?z<~DZs<Z&KnBTDeczfjvTWG4
zTDQu^zNzh-Ei>o;x%4;GI<@mj`<XWN-F)EEi(t3ml4tduUd?ico(3er#3h`cVEdgM
zht`aIW|4ehR=y7)NeE%IRD)^vle&h`VkfBi)`8=q97#fy7h_(Z+w!l5B9F>HS98Kk
zO;+uTd$RKal6W1g!&kHS<jl)9>6ve8^hTNYHSP!Js=Rx?L9?oJ7YLMw(ifd49q5Cq
zjN5(73;SLVER4OgeX!1H&|w|p;2}10!WtX(9UOA5%=uY!>Uep9)4+TIqnm!+zxGkX
z?{>>p)3H&Xo9|*CP!fmF*6w&+5q1b8Dyu3E^jB)cM!2HjL0A2N?BM!qhht8NOrk~$
zyLE4Sa<9bSJP{jp>yH`PZ2=!l-o3U#_*2dZ^W^{$o?uaRqtSh*)lMtV?hm#Q?br8B
TC7)^^j{iJl!Qs+sabn)z>{FN^

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-hdpi/rating_not_important.png b/briar-android/res/drawable-hdpi/rating_not_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..c10325fe114dd69e75297bc427d5d1530466ff20
GIT binary patch
literal 1839
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

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-mdpi/rating_important.png b/briar-android/res/drawable-mdpi/rating_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b2e1d5649aff4c8adb60e454b4bd77275dc071d
GIT binary patch
literal 1434
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(#^lGsVip*wxV4$->#x$-u?X(ACh=#L&{!#L3yw
z&D7A`#K{n**Cju>G&eP`1g19yq}RmAz{u3Z1gBn5V#qB3+U$~Alv$RV;#QQOs{r=2
zRVHq?IN~%9sy79jTOj^$!l_pu=oo!a)FMSSObD2MKumbT1#;j?KQ#}S-iv?<JA-3!
zA_D^xkEe@cNX4x;(|3Cx4iGu!oBQ^(yI_pS#sz#)Rve)&f+YnX4PU-{@jpquosTb1
zuW46@)lROY!qwi_!wLjmExwwS{fDnc+{@GJ(vh@}2l`u{%$xmw-sIm)ua?BV|727X
zE7$&<>CY>bsa{(r-#`6$_uV5oX0N?i!#dP;U$A{%a+{mc)4*p^97jabzW(R3q6S<-
z54u$<)+RHFIk5Z@u#A5*rJ>H?_|(-CK1bgBUCfvy;k@8p!P;}#E4TG>2(koTIGo(#
zro8&qV?&-}j#m@(c5Y)_c7VNtHQ%NyFw|k@Rjt*QQmicpj3U^rzHbX`-8VaI{iEdz
zZQZ`BxHF4CxaDzx+u||vwizE%H!ms`F03o!I(If|ffJiev#h`Z1@(o`ELhCf-fKKI
zp;2`MH=9pYo@&#YH;fe<c5|yJ^2+_JyU{C9d^wGO`zBuQ1pX&cA*XZ7pU#Lbc*T6F
zOL^PD^o!A}&S>sTb!paFIaPjw)p5REFIy(-tPW+Yd$vPO!Oz(6RuZG|<Idfx4mp)9
zS7v=WGOb(Xj!Ag0WuWzarp*)LZ4B3WJ-#Ovzn^Kk%x1Q*pMO^r<@D^VT+VdtN8_r(
zsox*8Xoo9`)p2h-$iw>MX4{_2Vm=?%)-g$Lxc{X<)b-x!f}D<>eNh5Ql2_fABsqSN
z_016WDegO8#+vcv<04;av4zKL1h-D(|M9>0)z*f1MmC0b_sT3;RPTC$N=r{yKbLh*
G2~7Yru?ji>

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-mdpi/rating_not_important.png b/briar-android/res/drawable-mdpi/rating_not_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..392eeb00c565a513412e8cf90a208c2fe8826e2c
GIT binary patch
literal 1463
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(#^lGsVip#M0Tq#K6_m$-u?X(ACh=#L&{!#L3yw
z&D7A`#K{n**Cju>G&eP`1g19yq1O$kUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dR<{@#
z7@3;5;4}}aHwCL(z<P1}Lm%iEeNfaQMKw$an0`P^c)|s8;7LC<518JIfC)P%?b;>=
z1}05U7srr_TW_YH*LDdMIiB8g=*QY4XCg9`M8brPCM}vGVm52(rbTQ1u!@PDx|FtQ
zV_@A<&q+zDS(hSi{4njFsG<2dy-wxW_bcIhO_J};{yuAa;p@w_#rG}0*FN7<eQxi0
zsqUjXY1??ZPo6DdoOw!KuHSuiz1eSbUB86^CpK`D2n5G9@@^5HEy*PHLjQ{NCN`68
zejARy)+?BCj$=oI@Ec)q&)Ez=zpFp!lquHHWh!!1z7f`wTdZR)%e3c#n2SiVU|;1|
zy+cY9SU*+h)-s-8Z#}?wCqeIAj8Lm$+HvlR2d^tx&Oey<*LwY9t_gGAv6nxXlx#nF
z&gT0J%L`d#J}|0sT})lj^<CS+kfUL%3)7Qh;xE`{$HZjazApc*G(lud)7O;Jgt>we
z%-jj?={u*b_;tYMMsRe;H;tqgMcySpKGZFH&SP<D7V9H}qf>3yY`k~-#p9<k?kkrq
z)H&iAW?R{AsU<hhIa<9||LZkIPf7a~X;Nz0Ww(A!eYtGAfaL++j#V3aFI`JaQC-6r
z?r@gV%<Z<6GHXavL6b;!x3S!^e#PgE)~Ab}OjnRUy?IO6wI1%H_bxc!7vIaYq@~Va
z&8FMD4QU%zui&5b{;`cTOU7@<`^I~j?!<)nCJ4kBZ=d>d>xoCIfioGrzZ6O<IvjeN
z7`MLRfxKz5)RqRjTlKGEnKzkEFJhl!`zW;afx`Lry$hxl?^&+puqkC);`K`|FN`$&
kr)6II-ygi0wT9b(VOMj_T4w7-nxLZ8)78&qol`;+00G$<$N&HU

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-xhdpi/content_new_email.png b/briar-android/res/drawable-xhdpi/content_new_email.png
new file mode 100644
index 0000000000000000000000000000000000000000..674b69b08715b9978186818d728ce4133d9f1ae2
GIT binary patch
literal 1703
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=GtDA|jrKPK>lYxt&p{t>#iJ_&diIcOV
zo2j9>iIX8ruS<S%X>Mv>2~2MaLa!T6y`aR9TL84#CABECEH%ZgC_h&L>}jh^+-`Bk
zX&zK>3U0T!;MA)Rbc{YIYLTKECIn1BASOKF0y*%cpPC0u??u3b&B=P@7cjp_db&7<
zRNQ(qJ2qR`QKT(>^44owqR~q;SXl)HT{PW3F7EopzUNc@5Bop7tOvPYraE5i)_Qcj
zb;c`K-6oALC8;&ybqhQvpZ&#GDSmCjU$3;YK4pA1xf-X-p4q;iV`+WcYTx^AC3jB|
zn>7q!4B8E%3obl7r9ai{Dc3$(R$b;}F>LY&nKJl`7H4g}CCFgN%-6I`)6>~PD}Nhf
zowSO>-D^NSQH-b9Iv*D7@nW42`c++m|0=8OWYcq}{wH3LU9g+u9^3f?ss%zm8x6LZ
zp8O$kd^6L##_$8-nhkp*dGE0BAGERHR%<k0@^8VBPV)oY8+fjLx)r>=!T!%5PMs!p
z=OUN#WAB@%$6n7#O1ia*Wd~1LgY^U3da<V+WqyC1X7!wwDv&$VB(23d<B>}LMlp}8
z_rDe#VKrbc3ubw5pIRer;pqO3JwNn%gV^rXLZWtj^NhI@-E}r`%v~g5&0gR#tH=M-
z_Y)uAEPf#ElF2KuFe&2sfpaIHFOlnuVBfyOM6c<xr0hhs$CpJS@70UD=DGAlu4Hhm
zP&p@Pe?X{W(j~!2qdK-X3q8KtXy;9ur6qIG|JdFO>r~n_4=m`Lu}t7r%AR<}Uxi1M
zcR9XOTD>c!CV+91#Utw-tD}#Fatb`}5Y=lg*uT#ASSa^}(}JIKqQZ9aq-pkvNuKv^
z$a9~vL#J;;zWA;bn|#J54k_{W*k#-D6F%Ghx$y7mW?SJcOc9J-vhO&~raG0xeLQ(c
z+keM?QQrpV2U_y`<eFc*3Lkh_vxNCn<n#vNLoJ<FhPCbUm;Nts-dp26<KuV6gB4T7
z4yxLn`qgH!Kv87B)NijG`2<!2^H~cYy-1B^+I2kbqGd$q>VMUig+D8;EhYrGr)&-}
zc5RR}v&?f@`0eGh2N#|iNH1P7q20v)U{m&mpt&7_2L%7`J60}y$JQ-eax=@5ZQt8u
z<EAigyQJClEzUpU*L+{02i!ZR6`YNE5t*QSbaO-gB!;@KQ}0su)IHhexcvU3BxyxZ
z`rBdXrS6n!=Iv`{)hhfzyy9%$hG|u=H~hEA>|P*xfGdG@1CxmPKQ04?g_?{dR|>L#
Ql?nrcr>mdKI;Vst05B|kTL1t6

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-xhdpi/rating_important.png b/briar-android/res/drawable-xhdpi/rating_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..da44dd82c3ab07009b3b45b638baceb90fcff514
GIT binary patch
literal 2045
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
F{{d4*A{+n!

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-xhdpi/rating_not_important.png b/briar-android/res/drawable-xhdpi/rating_not_important.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ff6c8d0e68f491e420faa9a955c9a6c19f8ea1e
GIT binary patch
literal 2340
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

literal 0
HcmV?d00001

diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 75b51e2dbd..79236a3960 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -12,7 +12,7 @@
 	<string name="contact_list_title">Contacts</string>
 	<string name="contact_connected">Connected</string>
 	<string name="contact_last_connected">Last connected &lt;br /&gt; %s</string>
-	<string name="add_contact_button">Add a contact</string>
+	<string name="add_contact_button">New Contact</string>
 	<string name="add_contact_title">Add a Contact</string>
 	<string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. For security reasons, you must be face-to-face to add someone as a contact. To use Wi-Fi you must both be connected to the same network.</string>
 	<string name="wifi_not_available">Wi-Fi is not available on this device</string>
@@ -39,6 +39,7 @@
 	<string name="interfering">This could mean that someone is trying to interfere with your connection.</string>
 	<string name="contact_added">Contact added</string>
 	<string name="enter_nickname">Please enter a nickname for this contact:</string>
-	<string name="add_another_contact_button">Add another contact</string>
+	<string name="messages_title">Messages</string>
+	<string name="compose_button">New Message</string>
 	<string name="done_button">Done</string>
 </resources>
diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
index 65b8fd01d7..07fe3d0b8c 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -12,6 +12,7 @@ import net.sf.briar.R;
 import net.sf.briar.android.BriarService.BriarBinder;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.contact.ContactListActivity;
+import net.sf.briar.android.messages.ConversationListActivity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -78,7 +79,8 @@ public class HomeScreenActivity extends BriarActivity {
 			messagesButton.setText(R.string.messages_button);
 			messagesButton.setOnClickListener(new OnClickListener() {
 				public void onClick(View view) {
-					// FIXME: Hook this button up to an activity
+					startActivity(new Intent(HomeScreenActivity.this,
+							ConversationListActivity.class));
 				}
 			});
 			buttons.add(messagesButton);
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
index b12ba8db66..53143108ea 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
@@ -59,26 +59,25 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 	@Override
 	public void onCreate(Bundle state) {
 		super.onCreate(null);
-		if(LOG.isLoggable(INFO)) LOG.info("Created");
 		LinearLayout layout = new LinearLayout(this);
 		layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
 		layout.setOrientation(VERTICAL);
 		layout.setGravity(CENTER_HORIZONTAL);
 
 		adapter = new ContactListAdapter(this);
-		ListView listView = new ListView(this);
+		ListView list = new ListView(this);
 		// Give me all the width and all the unused height
-		listView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT,
-				1f));
-		listView.setAdapter(adapter);
-		layout.addView(listView);
+		list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f));
+		list.setAdapter(adapter);
+		layout.addView(list);
 
 		Button addContactButton = new Button(this);
-		LayoutParams lp = new LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-		addContactButton.setLayoutParams(lp);
+		addContactButton.setBackgroundResource(0);
+		addContactButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
+				WRAP_CONTENT));
+		addContactButton.setCompoundDrawablesWithIntrinsicBounds(0,
+				R.drawable.social_add_person, 0, 0);
 		addContactButton.setText(R.string.add_contact_button);
-		addContactButton.setCompoundDrawablesWithIntrinsicBounds(
-				R.drawable.social_add_person, 0, 0, 0);
 		addContactButton.setOnClickListener(this);
 		layout.addView(addContactButton);
 
@@ -146,7 +145,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 					IBinder binder = serviceConnection.waitForBinder();
 					((BriarBinder) binder).getService().waitForStartup();
 					// Load the contacts from the database
-					final Collection<Contact> contacts = db.getContacts();
+					Collection<Contact> contacts = db.getContacts();
 					if(LOG.isLoggable(INFO))
 						LOG.info("Loaded " + contacts.size() + " contacts");
 					// Update the contact list
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
index 69dcecfd8e..1849d60ede 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
@@ -20,8 +20,8 @@ import android.widget.TextView;
 
 class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 
-	ContactListAdapter(Context context) {
-		super(context, android.R.layout.simple_expandable_list_item_1,
+	ContactListAdapter(Context ctx) {
+		super(ctx, android.R.layout.simple_expandable_list_item_1,
 				new ArrayList<ContactListItem>());
 	}
 
@@ -34,14 +34,14 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 		layout.setGravity(CENTER);
 
 		ImageView bulb = new ImageView(ctx);
-		if(item.getConnected()) bulb.setImageResource(R.drawable.green_bulb);
-		else bulb.setImageResource(R.drawable.grey_bulb);
 		bulb.setPadding(5, 5, 5, 5);
+		if(item.isConnected()) bulb.setImageResource(R.drawable.green_bulb);
+		else bulb.setImageResource(R.drawable.grey_bulb);
 		layout.addView(bulb);
 
 		TextView name = new TextView(ctx);
 		// Give me all the unused width
-		name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f));
+		name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1));
 		name.setTextSize(18);
 		name.setText(item.getName());
 		layout.addView(name);
@@ -49,7 +49,7 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 		TextView connected = new TextView(ctx);
 		connected.setTextSize(12);
 		connected.setPadding(5, 0, 5, 0);
-		if(item.getConnected()) {
+		if(item.isConnected()) {
 			connected.setText(R.string.contact_connected);
 		} else {
 			String format = ctx.getResources().getString(
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
index 99d2a79fcc..47747e3a1b 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
@@ -30,7 +30,7 @@ class ContactListItem {
 		return contact.getLastConnected();
 	}
 
-	boolean getConnected() {
+	boolean isConnected() {
 		return connected;
 	}
 
@@ -40,7 +40,6 @@ class ContactListItem {
 
 	private static class ItemComparator implements Comparator<ContactListItem> {
 
-		@Override
 		public int compare(ContactListItem a, ContactListItem b) {
 			return String.CASE_INSENSITIVE_ORDER.compare(a.contact.getName(),
 					b.contact.getName());
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
new file mode 100644
index 0000000000..a45ac9c8bf
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -0,0 +1,225 @@
+package net.sf.briar.android.messages;
+
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+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.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.BriarBinder;
+import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.api.Contact;
+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;
+import net.sf.briar.api.db.PrivateMessageHeader;
+import net.sf.briar.api.db.event.DatabaseEvent;
+import net.sf.briar.api.db.event.DatabaseListener;
+import net.sf.briar.api.db.event.MessageAddedEvent;
+import net.sf.briar.api.db.event.MessageExpiredEvent;
+import net.sf.briar.api.messaging.Message;
+import net.sf.briar.api.messaging.MessageFactory;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.ListView;
+
+import com.google.inject.Inject;
+
+public class ConversationListActivity extends BriarActivity
+implements OnClickListener, DatabaseListener {
+
+	private static final Logger LOG =
+			Logger.getLogger(ConversationListActivity.class.getName());
+
+	private final BriarServiceConnection serviceConnection =
+			new BriarServiceConnection();
+
+	@Inject private DatabaseComponent db;
+	@Inject @DatabaseExecutor private Executor dbExecutor;
+	@Inject private MessageFactory messageFactory;
+
+	private ArrayAdapter<ConversationListItem> adapter = null;
+
+	@Override
+	public void onCreate(Bundle state) {
+		super.onCreate(null);
+		LinearLayout layout = new LinearLayout(this);
+		layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+		layout.setOrientation(VERTICAL);
+		layout.setGravity(CENTER_HORIZONTAL);
+
+		adapter = new ConversationListAdapter(this);
+		ListView list = new ListView(this);
+		// Give me all the width and all the unused height
+		list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f));
+		list.setAdapter(adapter);
+		layout.addView(list);
+
+		Button composeButton = new Button(this);
+		composeButton.setBackgroundResource(0);
+		composeButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
+				WRAP_CONTENT));
+		composeButton.setCompoundDrawablesWithIntrinsicBounds(0,
+				R.drawable.content_new_email, 0, 0);
+		composeButton.setText(R.string.compose_button);
+		composeButton.setOnClickListener(this);
+		layout.addView(composeButton);
+
+		setContentView(layout);
+
+		// Listen for messages being added or removed
+		db.addListener(this);
+		// Bind to the service so we can wait for the DB to be opened
+		bindService(new Intent(BriarService.class.getName()),
+				serviceConnection, 0);
+		// Load the message headers from the DB
+		reloadMessageHeaders();
+
+		// Add some fake messages to the database in a background thread
+		// FIXME: Remove this
+		dbExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					// Wait for the service to be bound and started
+					IBinder binder = serviceConnection.waitForBinder();
+					((BriarBinder) binder).getService().waitForStartup();
+					if(LOG.isLoggable(INFO)) LOG.info("Service started");
+					Collection<PrivateMessageHeader> headers =
+							db.getPrivateMessageHeaders();
+					if(headers.isEmpty()) {
+						// Insert a fake contact
+						ContactId contactId = db.addContact("Carol");
+						// Insert some messages to the contact
+						Message m = messageFactory.createPrivateMessage(null,
+								"First message's subject",
+								"First message's body".getBytes("UTF-8"));
+						db.addLocalPrivateMessage(m, contactId);
+						db.setStarredFlag(m.getId(), true);
+						Thread.sleep(2000);
+						m = messageFactory.createPrivateMessage(m.getId(),
+								"Second message's subject",
+								"Second message's body".getBytes("UTF-8"));
+						db.addLocalPrivateMessage(m, contactId);
+						db.setReadFlag(m.getId(), true);
+					}
+				} catch(DbException e) {
+					if(LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				} catch(GeneralSecurityException 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) {
+					if(LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		db.removeListener(this);
+		unbindService(serviceConnection);
+	}
+
+	public void onClick(View view) {
+		// FIXME: Hook this button up to an activity
+	}
+
+	public void eventOccurred(DatabaseEvent e) {
+		if(e instanceof MessageAddedEvent) reloadMessageHeaders();
+		else if(e instanceof MessageExpiredEvent) reloadMessageHeaders();
+	}
+
+	private void reloadMessageHeaders() {
+		dbExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					// Wait for the service to be bound and started
+					IBinder binder = serviceConnection.waitForBinder();
+					((BriarBinder) binder).getService().waitForStartup();
+					// Load the contact list from the database
+					Collection<Contact> contacts = db.getContacts();
+					if(LOG.isLoggable(INFO))
+						LOG.info("Loaded " + contacts.size() + " contacts");
+					// Load the message headers from the database
+					Collection<PrivateMessageHeader> headers =
+							db.getPrivateMessageHeaders();
+					if(LOG.isLoggable(INFO))
+						LOG.info("Loaded " + headers.size() + " headers");
+					// Update the conversation list
+					updateConversationList(contacts, headers);
+				} 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();
+				}
+			}
+		});
+	}
+
+	private void updateConversationList(final Collection<Contact> contacts,
+			final Collection<PrivateMessageHeader> headers) {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				adapter.clear();
+				for(ConversationListItem i : sortHeaders(contacts, headers))
+					adapter.add(i);
+				adapter.sort(ConversationListItem.COMPARATOR);
+			}
+		});
+	}
+
+	private List<ConversationListItem> sortHeaders(Collection<Contact> contacts,
+			Collection<PrivateMessageHeader> headers) {
+		// Group the headers into conversations, one per contact
+		Map<ContactId, List<PrivateMessageHeader>> map =
+				new HashMap<ContactId, List<PrivateMessageHeader>>();
+		for(Contact c : contacts)
+			map.put(c.getId(), new ArrayList<PrivateMessageHeader>());
+		for(PrivateMessageHeader h : headers) {
+			ContactId id = h.getContactId();
+			List<PrivateMessageHeader> conversation = map.get(id);
+			// Ignore header if the contact was added after db.getContacts()
+			if(conversation != null) conversation.add(h);
+		}
+		// Create a list item for each non-empty conversation
+		List<ConversationListItem> list = new ArrayList<ConversationListItem>();
+		for(Contact c : contacts) {
+			List<PrivateMessageHeader> conversation = map.get(c.getId());
+			if(!conversation.isEmpty())
+				list.add(new ConversationListItem(c, conversation));
+		}
+		return list;
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
new file mode 100644
index 0000000000..f0ef7ec79f
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
@@ -0,0 +1,75 @@
+package net.sf.briar.android.messages;
+
+import static android.graphics.Typeface.BOLD;
+import static android.view.Gravity.CENTER;
+import static android.view.Gravity.LEFT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.widget.LinearLayout.HORIZONTAL;
+import static android.widget.LinearLayout.VERTICAL;
+import static java.text.DateFormat.SHORT;
+
+import java.util.ArrayList;
+
+import net.sf.briar.R;
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+class ConversationListAdapter extends ArrayAdapter<ConversationListItem> {
+
+	ConversationListAdapter(Context ctx) {
+		super(ctx, android.R.layout.simple_expandable_list_item_1,
+				new ArrayList<ConversationListItem>());
+	}
+
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent) {
+		ConversationListItem item = getItem(position);
+		Context ctx = getContext();
+		LinearLayout layout = new LinearLayout(ctx);
+		layout.setOrientation(HORIZONTAL);
+		layout.setGravity(CENTER);
+
+		ImageView star = new ImageView(ctx);
+		star.setPadding(5, 5, 5, 5);
+		if(item.getStarred())
+			star.setImageResource(R.drawable.rating_important);
+		else star.setImageResource(R.drawable.rating_not_important);
+		layout.addView(star);
+
+		LinearLayout innerLayout = new LinearLayout(ctx);
+		// Give me all the unused width
+		innerLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT,
+				WRAP_CONTENT, 1));
+		innerLayout.setOrientation(VERTICAL);
+		innerLayout.setGravity(LEFT);
+		innerLayout.setPadding(0, 5, 0, 5);
+
+		TextView name = new TextView(ctx);
+		name.setTextSize(18);
+		name.setText(item.getName() + " (" + item.getLength() + ")");
+		innerLayout.addView(name);
+
+		TextView subject = new TextView(ctx);
+		subject.setTextSize(14);
+		if(!item.getRead()) subject.setTypeface(null, BOLD);
+		subject.setText(item.getSubject());
+		innerLayout.addView(subject);
+		layout.addView(innerLayout);
+
+		TextView date = new TextView(ctx);
+		date.setTextSize(14);
+		date.setPadding(5, 0, 10, 0);
+		long then = item.getTimestamp(), now = System.currentTimeMillis();
+		date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
+		layout.addView(date);
+
+		return layout;
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java
new file mode 100644
index 0000000000..711329ec3b
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java
@@ -0,0 +1,81 @@
+package net.sf.briar.android.messages;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import net.sf.briar.api.Contact;
+import net.sf.briar.api.db.PrivateMessageHeader;
+
+class ConversationListItem {
+
+	static final Comparator<ConversationListItem> COMPARATOR =
+			new ItemComparator();
+
+	private static final Comparator<PrivateMessageHeader> HEADER_COMPARATOR =
+			new HeaderComparator();
+
+	private final Contact contact;
+	private final List<PrivateMessageHeader> headers;
+	private final boolean read, starred;
+
+	ConversationListItem(Contact contact, List<PrivateMessageHeader> headers) {
+		if(headers.isEmpty()) throw new IllegalArgumentException();
+		Collections.sort(headers, HEADER_COMPARATOR);
+		boolean read = false, starred = false;
+		for(PrivateMessageHeader h : headers) {
+			read &= h.getRead();
+			starred |= h.getStarred();
+		}
+		this.contact = contact;
+		this.headers = headers;
+		this.read = read;
+		this.starred = starred;
+	}
+
+	String getName() {
+		return contact.getName();
+	}
+
+	String getSubject() {
+		return headers.get(0).getSubject();
+	}
+
+	long getTimestamp() {
+		return headers.get(0).getTimestamp();
+	}
+
+	boolean getRead() {
+		return read;
+	}
+
+	boolean getStarred() {
+		return starred;
+	}
+
+	int getLength() {
+		return headers.size();
+	}
+
+	private static class HeaderComparator
+	implements Comparator<PrivateMessageHeader> {
+
+		public int compare(PrivateMessageHeader a, PrivateMessageHeader b) {
+			// The newest message comes first
+			long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+			if(aTime > bTime) return -1;
+			if(aTime < bTime) return 1;
+			return 0;
+		}
+	}
+
+	private static class ItemComparator
+	implements Comparator<ConversationListItem> {
+
+		public int compare(ConversationListItem a, ConversationListItem b) {
+			// The item with the newest message comes first
+			return HEADER_COMPARATOR.compare(a.headers.get(0),
+					b.headers.get(0));
+		}
+	}
+}
-- 
GitLab