From 4bcd20468730b646c769f7a2ac4428ddc9f8d5e4 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Tue, 22 Dec 2015 18:22:51 -0200
Subject: [PATCH] Use a RecyclerView for the Contact List

---
 briar-android/build.gradle                    |   1 +
 .../res/drawable-hdpi/contact_connected.png   | Bin 1316 -> 0 bytes
 .../drawable-hdpi/contact_disconnected.png    | Bin 1133 -> 0 bytes
 .../res/drawable-hdpi/social_add_person.png   | Bin 1784 -> 0 bytes
 .../res/drawable-mdpi/contact_connected.png   | Bin 1025 -> 0 bytes
 .../drawable-mdpi/contact_disconnected.png    | Bin 484 -> 0 bytes
 .../res/drawable-mdpi/social_add_person.png   | Bin 1496 -> 0 bytes
 .../res/drawable-xhdpi/contact_connected.png  | Bin 1094 -> 0 bytes
 .../drawable-xhdpi/contact_disconnected.png   | Bin 1168 -> 0 bytes
 .../res/drawable-xhdpi/social_add_person.png  | Bin 2103 -> 0 bytes
 .../res/drawable/contact_connected.xml        |  26 ++
 .../res/drawable/contact_disconnected.xml     |   5 +
 .../res/drawable/social_add_person.xml        |   5 +
 .../res/drawable/social_remove_person.xml     |   5 +
 .../res/layout/activity_contact_list.xml      |  33 +++
 .../res/layout/list_item_contact.xml          |  51 ++++
 briar-android/res/layout/transports_list.xml  |   5 +-
 briar-android/res/menu/contact_actions.xml    |  12 +
 .../res/menu/contact_list_actions.xml         |  12 +
 briar-android/res/values/strings.xml          |   2 +
 briar-android/res/values/styles.xml           |   9 +
 .../android/contact/ContactListActivity.java  | 247 ++++++------------
 .../android/contact/ContactListAdapter.java   | 220 ++++++++++++----
 .../android/contact/ConversationActivity.java |  90 +++++++
 24 files changed, 499 insertions(+), 224 deletions(-)
 delete mode 100644 briar-android/res/drawable-hdpi/contact_connected.png
 delete mode 100644 briar-android/res/drawable-hdpi/contact_disconnected.png
 delete mode 100644 briar-android/res/drawable-hdpi/social_add_person.png
 delete mode 100644 briar-android/res/drawable-mdpi/contact_connected.png
 delete mode 100644 briar-android/res/drawable-mdpi/contact_disconnected.png
 delete mode 100644 briar-android/res/drawable-mdpi/social_add_person.png
 delete mode 100644 briar-android/res/drawable-xhdpi/contact_connected.png
 delete mode 100644 briar-android/res/drawable-xhdpi/contact_disconnected.png
 delete mode 100644 briar-android/res/drawable-xhdpi/social_add_person.png
 create mode 100644 briar-android/res/drawable/contact_connected.xml
 create mode 100644 briar-android/res/drawable/contact_disconnected.xml
 create mode 100644 briar-android/res/drawable/social_add_person.xml
 create mode 100644 briar-android/res/drawable/social_remove_person.xml
 create mode 100644 briar-android/res/layout/activity_contact_list.xml
 create mode 100644 briar-android/res/layout/list_item_contact.xml
 create mode 100644 briar-android/res/menu/contact_actions.xml
 create mode 100644 briar-android/res/menu/contact_list_actions.xml

diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index 3e6d17c847..f06ca62b13 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -7,6 +7,7 @@ dependencies {
     compile project(':briar-core')
     compile fileTree(dir: 'libs', include: '*.jar')
     compile "com.android.support:appcompat-v7:23.1.1"
+    compile 'com.android.support:recyclerview-v7:23.1.1'
 }
 
 android {
diff --git a/briar-android/res/drawable-hdpi/contact_connected.png b/briar-android/res/drawable-hdpi/contact_connected.png
deleted file mode 100644
index 9fa452b33cdc41c6771b7df4bd6d24c60458d851..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1316
zcmV+<1>5?GP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px(-bqA3RA}DqnNMg`R}{v-@4lJI%p^0(jJ28svQcZgh~hk?i&9!^5u~d^7D}Md
z+Jy_DZUZh0Ze6%=p+XCxE(CWK#D8rmSmZs?bfK8iHV_7Cok?b#Ofoa?eqH1R6s`I9
zMlH;@oHzI0^SkHVch5Nw=%}NPI_hWxV$>75uIorjlI#J{9sXPc@I=yr@B6_U3s5K&
zvH(U%ZU@i@AR9iaNSY-%1z^(iyviE`P$(4QBzH>MPhywEge(Z41;B=XGXP>V5UGZQ
zdnB((df@wh^R)rEuDeUpL6SSIMSQ+&D)FSM?;Wn~&b)26gb)A_t3BpFKb_6o2GEzz
z*(|9hfCnTmd!Bdil>)e~Ya|^a`3WG@D<;Sf1?AC`<>L}-@ucmhLHy}4vS>Byrb?rp
zi{rUdrD-RZ%322?BwZzW!Sg)Zc7Q^mkOc5KiTADLLL#N+*y+-j@h+u;7Dc{%P6={i
zVsnx8iDUWmjXLATC@J9=0N?q(ztA>-LZLvCUjh1XuIQ9L`)2N=p*@X3<0!xOy%21`
z()69g%%u~(H+%boJis3%o%MZRtDVJJ%aQ{F17m>p%@v*5FV2@n`-hv`NTj5dcm8=#
zP{t^o8w|D#f4n$!YogmrX6!ov(#2wNGID@Ip)f-7u(fP_I$rspf4I3#A^>8o#sdh)
zER9cPZD#9mEB*VgU4I(GZ36=Xe-w+wzgIJlS>>Tk05}K;iIkc{dm4jMboYk@4DD$Q
zCQ@nwf~14tn$Z9N*iLe|UNOPg>CzG7C@)db0Z_(Ke(ZGVNWEeL0K)*bM+PA2fVD{E
zhl1I7my+uZo0Y;T-lb%ID43O)0B|4@0M~W9NsP>wO=a|C`FPM`gu(Nyf)+J;vV45L
zY$||8T-WX15I}fg?FNttS}0k|CsFSFi#%a1p9C$G03;;sc3szO!~-b+J8VF+?`U;z
zB4sn}PLC5Qo7s1?y4MCY0Cq@9ts6j6Cd?|E-J7(T2C=s1_Xe@<P1+2gNwN>XOE)d{
za+fj<pjS&-W$P8zDa)B`Z)n51J@DEqu9a+9=?u(Enp@82U!mQxaLqXY^BV!E0+<C5
zuRZ1?+4hH#ELye4d;}mKu3g;-KpntC<H+7Pleyifn`*lO8g)~>aVB%yII@x+hBmAZ
z!1sL%;4XlM6GPq@^+-_r;vF(ZJx&aH01c9NLmSqA6Z^hj12~z^+3dyf+$krfwq0aS
zOuRUrJC)AaEWk<6^J-Bgb5}?;O4CkXbCC;686y<s&I3Yokqf11r_UHPBwdLz8=V4h
zKb5u4#IgK28?Zzw!emag0ZS9d^5>T7WZVy1Fwp>bp4T9G86X;U#;5NjW*A{0k-+qw
z#7v{kcv$3L_B^i<r3c`7-lU}K#wdB|MDNY=Osq%>>kX&nupx!=Ossh6MDI;wlmu|y
z_x<QgN&x8Z@Ba<JTgi;xy*1J8Z5?i<vs-N37^T-*)Gvq4UtZVL_h09J=<N^k5`G5o
zZLwHvUt7g>-6Vj|0sa5lDo+*ohU6gtku<gdT$OZTrFVX(wfG+paY;K#?gzB0<}Sc{
z0ImUe;CbHbYwo@PCM#(q>?rh+e5Sn)V2b3M)n0$W`EW=kB|Z0n13=^-I6CU6qmDY-
akp2bu44pSGze%?M0000<MNUMnLSTY3>~8k}

diff --git a/briar-android/res/drawable-hdpi/contact_disconnected.png b/briar-android/res/drawable-hdpi/contact_disconnected.png
deleted file mode 100644
index 9de4968499c5c464a53beb423088bbe7c618b5b4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1133
zcmV-z1d{uSP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px(CrLy>RA}Dqna^ufR~*GZXGW8#F$p!Hya!68ih_;8d(cH))S?J(Tw4U8;Qv%;
zS8WkoyAdRc&~{bsZB42uO3m(qLGVY6COUJv@Cvr3m`r9y7jstgW|;f^o_oLde$PD*
z1{h#~0S4Fv)a?Q5x^CJYku(bI$X`DLmTbR>F}6Nh0##Lw0W*^J0TaMj{^^PBN0ROV
z^C5&M9}R)3s<uixVEZ_57#IQ?KwDDVHu<@cpI3o7Nmp&(i7~$XU<B&AK5Y9`CNK=N
zfycl@NsGXnnH~owZBI%Xv)uqzfIE^dhY;raN}#UmhV3(wPWbf{k4U-?T(kYBr02F@
z0dMNPDQOEZ3VaS6x4l==3qZDKC0z_5w0lmVs;Uv-9B@?9D)7|yr5NM&4UTh6(rMc}
zbJ_g{{1jt+v5|3_8w@H*-vVDr0=NNu7h}A&(TPYYEfhr&C4CB%lBOk%7e(<$N~t#l
z%CbBQd<`J!n(ZHAjL$l)-;~mFS(d-&(`s7M9$<S)X};?Os;Zii^o{M8`4ss+#@OEM
zDV9=lS(bCa9!Z}_`m8L=`zfUd>-m3Uott(DIF%olBwgra!~GvZ2yIChY%kfy_Ng4R
zI|P7zk`CG)mUJnEu-NSm9zs}@bO{&+4g&kSM!@#Tocuxv;W|A+2;sV<1xdre$*vHn
z>v{(;1GH_=_CcS`+HTvP$+0^pkQ>&Kd`>?BZuUBR+c$HpA=^jlx^8S{1-1eE^J%pR
zEcIapma+_K0{d-m>zF|9k`t0zk{$xDdam!KS6NH7BuxN2J0>7$yQFcTW&814+NPIi
z0gr9BfN@FNH?sn7lOf9o`mhhy{M^YNSk5!wv^{RS*@yg_S$;ROG+*8ffv3QuJlHN^
zOCJbq$+4O__S4M}cn;jP-I6qw^?a|(XH?RZq?YZwIfu>&WU+Q5>;5rGhx)Jrhis1l
ztCDWKPcXi>6KA<RZ@XdpL>~y8$a&3&5Z)`**DL0(04tKFtExKItIX@VK9(;wE4Ht6
zQ;psOZs&{m>AJ3`dXW5-?bA8N?QFqxhd>BnRnq0$4@QBrRaG^*m3$uSY#tlimqQ4v
zUA>W|lpYjCu~X6kpajN>qL@o5d6P5WkaQ0CGUqcJV_diD-B4pHisCO|Qqo>Y)4=Yc
zDE>|<Eq7Wrz<J<k_KJQ1e(c$$KBYuimbZWj+q)(00=_7UVkM=t(1ERT-uCXC$FIQ8
zF~$uEMs-@VlFk5Y8e72gtSVbs%QSO`9hLNsv6U||7dtTt`eH5G9+xy}doo)nAJ$s@
z4~ea|4@f$0`>>=TpkcesYl9ct4M~kma21#Xt^#*L2p`VeU4zV+?V0Q-Oi22dy$;-y
z^l{niYwVAvq!HWiyx;)3{(@tG0R|XgfKA~a{i+eJYP;8)00000NkvXXu0mjf7%mje

diff --git a/briar-android/res/drawable-hdpi/social_add_person.png b/briar-android/res/drawable-hdpi/social_add_person.png
deleted file mode 100644
index 38b91cc7ce29dac49f4f048c4e7738bde2e41bf1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1784
zcmaJ?c~BEq98QrK1eK$V4IsJ(JV27{<^Ylq&ICy%luJRBmK+NNNOrSXAYj#aaCo#@
z#SR{Lj0ei02(1@LMUh4;M{AYCDpW-*RY6B3)T7-XVE-uHncer^Z@%yQoo{wyWW=Ir
z*3Q->5^0(wOcYJ5p!v0$Onl=kh6{+r2^YuXF-S6=EyG|^kP?x@fJ7}zfumuWGDmwA
z_9KxdxvOI1@px%CUxBC@GBbvuSEB@*MDh#JqcTN0j018wMWqqa25Ntx0V<`C7RQx>
zQZxikRfXkZa7=DQtRgpE!Bf%#`~g2bpAb;PxD3#%Gc-EBUPv3!<r90enMngiAb7fv
z_CBb1X(SMWU@*XCfOG}u4FTR92E+k*9G(}z0wItIv6!F_9Rm4WA3g{HqYsVnhAETz
z(W1~%U&KjBOT}@N&tzt2XEU<d3<OJILOdRi39^_h7M(!QbvYVbrl)IkZet1}Sf{{L
zD6T>@fLT!{M>26CjfnJp3Tkv*R-+p&6HzdxUWPIu253%c3@DZUKUA$AN9*ut_(Qz^
zDXfdlL1AVztV1#}1<|-<H?u30AA-R$9Km7{Bx9_Kk*Nrd=u#0B2#Mh`AV4Zps5EBF
z2tz96OEfxMrcuBWk&s4cFjOifpUV}6fGjba8w`pdNDT2f5Kqhr4hah7LOz^eXpAdD
z6q#yRgO72QAGn+ex#nR|ql9M>jH$9<WhjQIfsv&7s)=KPCe$0{DkqMGH6fQt1j979
z_Ft_YGZFJ+-i{A0aTp(cSVPP^Mhx~lQlKYsU(zI^pjds^<K3O<A4fShv3F5j%0sV^
zm-pw(uT-X?LE=Y?qc$xNd#zizz~8jUbZ_&T^;V3Y&4o<Ofx<!?=P0`hTe28!@I2Mk
z6@L1ez(j76$=SC{9I+mXO2FoIU+CMrvL&*a)7&BQuJkzYv!#;d<TF$nC@8i`Hgxw0
zOjGOgen-9cyzT4Tur)<(cOl6mmCQe8pqZ>bUpv1irC87-4s_|Tz18-I1t?jEuUm4!
zWku<>d^_Ol5>idjzLw>c&RfZ>g7#KQ`z1TOY;C2l*5SIPVn)i}DGm{Ht0*r-9)ZEV
zq~hMH{`<@Fh6)SwqNZ%ykl4I)NDj}-MI0?SRdWpk+Y{rjM#g$3Imchpzfx4&#Kc<_
zSr=0h`op_&G0E`s@MJ1kcC_{KjU9#qdyWL|k84ePBlq}~zVO&e^t_SmvV`7aV}w3w
z{3dAArdr1~iT%J5n*~+SpGR)|ax4)a7A7XSQZ0}}zQ$SA<wenF@ARGnDi;MTAE0EM
z+i7F6)U0(M;8}Rz)b8i3D!nKloc!D7YL^SmejP#fKL%1tuJQchy0-dP8MJHmxn?LW
z4wu)FroI|>aHwra21)hL&o7-<vG?u{(;40M5@X*-_S#($Pn6l6O(kt!4?M!KzKAyM
z?8dNRi#p4n8d#?(9@a(6Oq2A@m`hoX{kCLr89IM*)4A3B+k^5V3wN(u>nms8>t4GE
zU)^|67{;noKI*p0Z(!eLS0osUF0M)<mv60jkTBhsS0C(j&*|W)x0;kG(q}+8`}o{p
z#PGVz(pWYdrc%G%d4j*^Ve#?Xp+=Td&5AD`d|%)(XuW3kZjz+s{$BEP?q7SV7tb%7
zmT0>_=jM!~^fwvk9KZdI)h{XZId+GaJbJ^ZUtZnfTH3IyquXayeZodfQ@wrk%ksh6
zq32cQPcOzg47mYU(qgvcrB~N%j<>7O={k|=__BPH$VhX4c;;CWXZ@#go^&9e>i=ra
zn#R`aPuzQWQR>jIS`WSmUR|+%P6Fn8A@gZIel{ROaH!^x>y`w=cQXp8{45uk@j~E8
z&GE>pv9~mO`e*sh%$&8)S<qRhrfh%QK(jqq+IXB+(t8fwC|sJv)?Q9<o6?r{rRJ%j
zKe26IH3<$`MO`W{X}?o9HTB&|QH<fU*KQX{C);mQ-(IUdZ2lKX#1Wzs!Aa}>0XVv|
A7ytkO

diff --git a/briar-android/res/drawable-mdpi/contact_connected.png b/briar-android/res/drawable-mdpi/contact_connected.png
deleted file mode 100644
index d91970da5b783896c4d9054cbd9e37538fe20d2e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1025
zcmV+c1pfPpP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UR^;9U7c0hlT(E1CB{V
zK~z}7?Uuh!TUQjvzu)_=pYe~z2}Bqy+Da`&>H@rHO9+)AU7ayfHq@wV)tx_}1AE)4
zQWmyIQHLt5VL(L{^?NZL5;Yy#3fUMH5-8x<zVDt6jwPfT%%f?S@?GBW?s@m~&bjxT
zFL0&*yLj2a+1Xh*j-y2cj^mik&CUM~!1KI!lv1+*#sEM>c1S*{R4Tu}aRATr5QZUq
z-%pd6i45+THb-;$DCM|_0Kj&jU)1zTV#w|~8V^NK4T9jL7kg;{-}ey&0X)x}QHr0w
ztT{uI3oU;1$??b8k?1BJxBwtl%%8iu@%>6>?fH6AZWN+d*2?`b46D6w#0Dr9i>Op8
zC>H(c)-gZNPZ_tobWqL?+nc6M0E7tS^+yN_v@1B;SAVQ7=T;j(>vl3DUsfu?)_D*E
zGEkgppWw6k#p4gB%gs3|Xo3W#PpAMw2t>rfY^|n#*jULtO{DDCVHj4=+C!aF`!p%{
z@>3?+-JF^v1(5#S>>`k)qMj}{=kik~sTA+|zMqZ_pcJQH)|^y%>EJdMG}+y?_w1X_
zQ){T8%S#8hU(}owi0Rk>k-^=`g_g<=+Yy57)%zk6fe>VN*p7U#&{7idZY%)L^C!$J
zj?6C}-!g3ilym>QZzd=(ZDM}$_*SQh5zq4{E(B02l|YK0D@56Aqb3jGCHoZtA+C*@
ze6A2>N%)@U4F<5*YLeql0v#&q?xDM!1Q04}CxH&hagur<fW#?wOdJszoB@&sBK4?)
zgjg~B2Lp=$#fphKNC2o?Yt2A_AP6AB;GpIl9q#Hzx9P~`3P8c(u5KLEoFi)`s8*{N
zy9HqwY$sCK+gQo0Y4>%9i+K$pgmwiRE19)K3VUG~ZpZ2abmYPF^`t%8S9=1HxYtl1
za<s4Zepydi<;a8BjR=CR8-=L3x}19?7N(bh^D=RIjaZn~<=ms|g{Uclt+QgBvtHEe
z_0HJX*v?_Y@!hnv@{^qc2zA~tBFNLj=-K0;9qsa)APBZ&1Ngp=Fbo@SzdQchuRpr)
zZ~x>zeQ&NcG4z&A+o<0-26R%;JXCw%eR2KUXOD*(ZpMBURD!Kyv50!T9)BG7Jb~{Q
zXGn=<NJMx)2r8F1B!7qS(;#N7;T_XPUrXkuWS5RS#A{2|i~UzjDT!H-W9%Nf9T9mF
vhT)qxrDv&BDj|xZUT-&p%;%M^be8@C9l6@ui6}FQ00000NkvXXu0mjf=ak=B

diff --git a/briar-android/res/drawable-mdpi/contact_disconnected.png b/briar-android/res/drawable-mdpi/contact_disconnected.png
deleted file mode 100644
index bef15c40b285d783f8586d6e0af2476ec8c609d7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 484
zcmV<A0UQ2_P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px$o=HSOR9M69mOoDdK@i1%iV0LEBxkdb&|*R3bT&d^)GtD7gN4MJMjBhbh#Cv|
z0;2^DmMCNk&k#CHG_jc$?vF>%gje3pynQ=6J8xlw4c3gUG)W>-25LaXK8=8Zs*YDG
zKt#@f6JQU>0bllO2lxiwfqPZG%~XJhRDcVh2#kS8-~|XRBmnk-BcKdSfooMA{aS#C
z902FQ9O$X4M#Kxy1PZ{7sy;1?&&AmJCGY{XRP`-Nu=n0O=N^DVpy8Z*_TJAH#cxOO
zwQT2YRsD>6t`^(2+}5(#?TCgeTG{7GyW4VlK+(7oSKt(wM4fqr2n8m_6<>he^8n~)
zFl+iiV4SflP_qUdW*}f_T(u+uDmG-o3<QM6RY`LTR*ppiMmAo94AuyYYm`L5z-D_j
z0|8az8pIZ0t`-9I3<T7HaFJ6k>w!C<WV1aLEVpD_$p(>G>J(^-NFl}I1v91TGJB4?
z1zmHsj)>$FES?8CmfKD3hTi*`bM6&r0LRWb@4fdi%6<jxnjH`S_k-k5Jjqu1DBWO#
awc`hHo}fAs1vriX0000<MNUMnLSTY+5X_AL

diff --git a/briar-android/res/drawable-mdpi/social_add_person.png b/briar-android/res/drawable-mdpi/social_add_person.png
deleted file mode 100644
index 2c9899ec8a0368e314306dd6525edd74932f47d2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1496
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(%+%Pz#K_gu$-u?X(ACh=#L&{!#L3yw
z&D7A`#K{n**Cju>G&eP`1g19yq1O$kUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnrq&
zG!Lpb1-DyVaO%|uIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1zo)^j5$H2hk<>}%W
zQgQ3a^xfXdfg;C@11G)t#S$2P<hau{^A$6kE_iL(5TLV7NK9OJP0Wp?n}_xv^vXFJ
z6cBLXP*SLXV@rfqQ!l?thmyvu(yJ+d_-Yz&cB@@KIaNgN$3%mfcYdF(ytgsu_P3Nv
zd*<;(mp$^<5b;vo!W7aNQ^3o2P_y9ap#qCP`x{igN!GBM9yrgdTfkm+(57|C^G5MC
zqCHLg59EKWu2{;;a!}-k`CR6u2@*ekY+1GXvB(s5H;2Yd#=Q#!Y?eeg+XS;!`EdQ<
zn6+a^-`!@hvvV#91suug&t50IcsrMmYND9&-N!#_Chz++sX_YKJ^$}%s*%d)?mykP
zLX%Pa!HmLKrsy->&&{U4l3*4r$lk;iwzGo$aKRTIb)Reg2}esL-!-I`9lF0D@Mr9-
z%L+gE#O|0a3Q09Sopzc3*g-~%<UAJ5q+@R{zvh@ApwpDw_J~^}ea-a)Y!>E5ypy*i
z-z?~NcHb&<u31@aogw4T1coielR1)W4!x6jkg<+k^#NDTrldtLxhAmIH)I`)XA3m^
zy*G=0k9*O=e#Kc!6v9I%oIM$K)IvS#qjKwtBQk3v-mPbLKII@?(c9p6;lZ-S7Z;uB
zJo3@&TGln*#w*q0>sc>(<owLvK4;eqeY;r3N0;mq?!L9`myVjleXeY+s)Exc%f#?c
zmy;HsN^ZLLY1j0oB{O4R$$6Ffn*BN{)TinH|FmL|jjg-Cw5Y;Ui-Q+)jAia?<lK5F
zY5nobGS(xOhe8A6%r^Awm5iKOWBPgTGM@W~%z`;L-1~d`<75VAhPRcSd$X04q(Eh@
Mr>mdKI;Vst0IBOL)c^nh

diff --git a/briar-android/res/drawable-xhdpi/contact_connected.png b/briar-android/res/drawable-xhdpi/contact_connected.png
deleted file mode 100644
index 4341f01a1a16797592c31e81c119d260cff7f9c9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1094
zcmV-M1iAZ(P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px(07*naRCwC$nmuS;Wf;eQ_v_@li3v4Ut)bPpv`cs>=#;woK?lLXK?(__;O3-L
zrsANJvxEdnhYqC<RlBxR1$oJ$i?JyoYH35-BsXcA`{|JXfy*UBZ*tDLC%x|<4&-oh
z&+~i#=Xt+h@bdEV^78WX^6E@wk_u#IS>PBj01N}K=pJAbcnUlLiom9GuJ+OxU}inQ
zY2Xxa66gbZfo}cFbKn`U4XgkUfF<YL&XG32%-#Xc0j95=*Hv%0LXPmN=-LDv@Vj&F
z?;~Y^nVkYY0nX@4mw>Da4^RebKvnlSJum3KqUV7!<4@oh=iGx-8(?Prz{kL(>Uv3!
zx`6fJw<=FR__Fxn;A^#W`~AMSnqBz$+rgVV8`)7{2-wx5KyAZa;8*9|R_Y8evp0Y*
zfU~O8IlX^ndVX!@An%-;8o8o2qpob}2L1r9Ip_XOjR9u%E^rBWRbRaecsM=3_DvM;
zpPL%_4mhEV2!O}HtaI+Kwi{q(<G@#{>s25(dAZpA_WPyJqpV){?*-TI{y6YFjG?yS
z2j|>k+YB(X*H!rAYPgu5U%M1%&oVbPGOIuHz^Y96@1XC?9<sr^sI;#pQTV19RmHw2
zmShb8K2kSV0&+<dzR84~VxJL9at4^$7;qlg0fNcP#qOlX@QN9T;k=mQH^9ttzy+XR
z_3%;D4c?1LF&~McAGjd4*fU^EX;)S{e%-E_Ttn=#n8uPY;5|)d0RBnAj5cKG6I*-+
zm{|ds2nRa{9pOcs1v46Wm4FE`MsI-X*Ele!@xywG)-~3}Gzg5h(iXIm0sWfO=Yf2_
ztNt)8r58&$)jloO$PGBAiAe#de|ly8v$Pl>mb%zZHmo#7YQV4>ni^0UI9{7biveN@
z*AV)|8jAtF4O7#!sVcVKxC|HodX9hrJz|Z0F7Q&Q6$6SIcV{#aNt?nIs2#CJZom^Q
zLZsb*XJU=TfNlLIUtG;Dq^0Cy$%}0}E(12%+q5VHnV)8cZluKkv1G)yBGwlhM70oS
z3s_QrTd(Y9PNc;Eu~gI(EQvMR3~<g>fkj|L-OW&n>i>|KHh@L3M&AuO=gPo>R$_Lw
zZr@gkAzUtB5M!+C0l%rC0eCY7Uq58n7F+BKBFpUU)fMywzHj5#4`Ua^v>dwus$aL%
z&{TlY`}czDNf%x*N5!xO+-jxnA8IJ<oLdI&Xxv@Wj!mLc%#s-Hh>1iDkZvpO0-)Nk
zW0OSc&#KD{#Be)_xj=IkYynr<+o;SnfF)7*aOnFOxO$lFa=$qm1zbmOk2jdmxd$W~
zOz7MrGEGKw<{_zljOff`a{Cz3nFl4COi1NXSuZayFE1}IFRxD3|8PgMT?Y<&b^rhX
M07*qoM6N<$f=^ryhX4Qo

diff --git a/briar-android/res/drawable-xhdpi/contact_disconnected.png b/briar-android/res/drawable-xhdpi/contact_disconnected.png
deleted file mode 100644
index d0499ddf1ffb6335c4b4f48d42ffed128d863a62..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1168
zcmV;B1aJF^P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px(N=ZaPRCwC$n$K%gR}{xTnPl=qW6}=V(l?c$G$Lphawr58>cR@9icq&*w)_4m
z-4<MS(}jg#n-<%J1p|R{u!{<kl-N`!4{ICisEL`G%yco|A&(L$GnqH<>AWvIn9CdP
z`QGn6_r7z^y^tY8h71`pWXO=AKQYiNLuQr(CV&G#0eD?)fHLqHSO=a0Wp}T?G6I;{
z7;qFg0vrbR1N(qc{pAI)0Xzrp1NVRxci()e1u(OBfcF5?Y!B&aM4lFp)>G3{1|0a=
z-G6(j1TeEBz=yyI&2$CGY48A5pbl)SJ*fA2wQG7mEYG+DeCzJ_QZ0a)jRUj5`&#Q2
zy&3`j0ak&Bz#m%ckM+I)Oag(P!@z66mfjER|33lq?*1%w0+?A5_!u~;H9e^Q?*j|K
z67ajbH~y!eAqj8{IIZ6edCMs9EAXYemr^5unH>W@0p8H8j{qU?1F+!kFFNdZR3dx;
zyd{qq2L1%Dy8BY%0+`t}@R`>7wq|}2_}bkcbxGhuz(>GL#Ks2jxw|hXCV-g*8vG$`
zTmW<K{!L7q>qX$QnnS=NiLlmbpM!hc@ID2mBD?ul?*4sTpR6zpmx3VJ)IQVDMq3Pm
z;FmBAE1mS2+XJ5q`pi`%<ea<z7<b?z8*{Q*5r+$%_Lu8$_NRcez@|2(MPR;%A^f~-
z4vWKCaf)96GaCdh0pnVS4}ojFirwV}b>Nz84~feqaf{sprsQ^2wQsolU%k%aWb;NO
zvOFPfu?sMxWCq{?a4W%V_LevxPBXCzU}kyXR3zA0aQCgGMlah7;!*)liDUN#(E6HI
z%s!yl{%#6t8h6EIK-{L=*$dk7fN|yYt(5iwP)dOSC2?u-Ix4PR7hpn(NnSxn$=z#7
zk6s)~;*=N1i8ur(Xrrks>|G;0Sc}vU_KRyQ0_=;VrcY8Nz!Pz5h+`}Q900~50<5P<
zfc1y~W8xZnF7QgA9RZ#y?jBGgQb^G_3Xuxbrnq)pfOQoiS^`X_NPx+R02}Qr&vpfP
z&Q5hVNRa@6IOW7K76HmM3!GIcT~q-xQHVoPoT}njjzfTFzzRDD7jMgO(kO~ci`R;{
zc2@v*-v*ZT&27-E+aFJX0LR6pA#Tg!+WpU<yH|nRs>Eyor_F36LH8e_SvGH#%WsQg
zto49JZ8XUB&LlYdXT$+<TI@wZWR>PwT`TWCZ)OJ*nEivmc{TImv>LkrT3^?-(bRx9
zfh#)y@73UQz!ll9iOcnN*8ZMCVRv5zZYu7ss1!BZLkF0Z&5AhO6eoHjfbgB%Zdi%P
zWivb1gV{ev^K@uiw(p2bN9g!uC=A0&5Ckj0yQ;v{fs;WHG{P`kifQl{<@&I5H1>tN
z|J`Yy+2LrH2=?#sc!X^KUXX~8@82sj{}G};FG=kpM1NkB+eL`}yePR#_?o(_vKcaD
i$dDmJh71|{75@S`3cP741Rj6@0000<MNUMnLSTY7s~`^m

diff --git a/briar-android/res/drawable-xhdpi/social_add_person.png b/briar-android/res/drawable-xhdpi/social_add_person.png
deleted file mode 100644
index 2cefca64503310db99633e3b989344bc96c8b75f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2103
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
SCLS>V%0;1(g44X@ynh4GY&7Bk

diff --git a/briar-android/res/drawable/contact_connected.xml b/briar-android/res/drawable/contact_connected.xml
new file mode 100644
index 0000000000..95e7a0bc06
--- /dev/null
+++ b/briar-android/res/drawable/contact_connected.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:alpha="0.56">
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,2 C6.48,2,2,6.48,2,12 S6.48,22,12,22 S22,17.52,22,12 S17.52,2,12,2 Z M12,20
+C7.58,20,4,16.42,4,12 S7.58,4,12,4 S20,7.58,20,12 S16.42,20,12,20 Z" />
+    <path
+        android:pathData="M0,0 L24,0 L24,24 L0,24 Z" />
+    <path
+        android:fillColor="#95d220"
+        android:strokeWidth="0.76779664"
+        android:strokeLineJoin="round"
+        android:strokeLineCap="round"
+        android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896
+C4.55452,7.53099,7.09451,4.8236,10.394,4.14714
+C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295
+C20.0698,10.7495,20.1616,12.4612,19.777,13.9758
+C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771
+C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z" />
+</vector>
\ No newline at end of file
diff --git a/briar-android/res/drawable/contact_disconnected.xml b/briar-android/res/drawable/contact_disconnected.xml
new file mode 100644
index 0000000000..d8ee38c1e1
--- /dev/null
+++ b/briar-android/res/drawable/contact_disconnected.xml
@@ -0,0 +1,5 @@
+<vector android:alpha="0.56" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
+</vector>
diff --git a/briar-android/res/drawable/social_add_person.xml b/briar-android/res/drawable/social_add_person.xml
new file mode 100644
index 0000000000..982183dea2
--- /dev/null
+++ b/briar-android/res/drawable/social_add_person.xml
@@ -0,0 +1,5 @@
+<vector android:alpha="0.56" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M15,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zm-9,-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9,4c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
+</vector>
diff --git a/briar-android/res/drawable/social_remove_person.xml b/briar-android/res/drawable/social_remove_person.xml
new file mode 100644
index 0000000000..4adacc148f
--- /dev/null
+++ b/briar-android/res/drawable/social_remove_person.xml
@@ -0,0 +1,5 @@
+<vector android:alpha="0.56" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
+</vector>
diff --git a/briar-android/res/layout/activity_contact_list.xml b/briar-android/res/layout/activity_contact_list.xml
new file mode 100644
index 0000000000..acde6fdc93
--- /dev/null
+++ b/briar-android/res/layout/activity_contact_list.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent"
+	android:orientation="vertical"
+	android:gravity="center">
+
+	<android.support.v7.widget.RecyclerView
+		android:id="@+id/contactList"
+		android:scrollbars="vertical"
+		android:layout_width="match_parent"
+		android:layout_height="match_parent"
+		tools:listitem="@layout/list_item_contact"/>
+
+	<ProgressBar
+		android:id="@+id/progressBar"
+		style="?android:attr/progressBarStyleLarge"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:indeterminate="true"
+		android:visibility="gone"/>
+
+	<TextView
+		android:id="@+id/emptyView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:textSize="@dimen/text_size_large"
+		android:text="@string/no_contacts"
+		android:visibility="gone"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/briar-android/res/layout/list_item_contact.xml b/briar-android/res/layout/list_item_contact.xml
new file mode 100644
index 0000000000..69ec0383e3
--- /dev/null
+++ b/briar-android/res/layout/list_item_contact.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:orientation="vertical"
+	android:layout_width="match_parent"
+	android:layout_height="wrap_content">
+
+	<LinearLayout
+		android:orientation="horizontal"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:background="?attr/selectableItemBackground"
+		android:padding="12dp">
+
+	<ImageView
+		android:id="@+id/bulbView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_marginRight="@dimen/margin_medium"
+		android:layout_marginEnd="@dimen/margin_medium"
+		android:layout_gravity="center_vertical"
+		tools:src="@drawable/contact_disconnected"/>
+
+	<TextView
+		android:id="@+id/nameView"
+		android:layout_width="0dp"
+		android:layout_height="wrap_content"
+		android:layout_weight="1"
+		android:layout_gravity="center_vertical"
+		android:layout_marginRight="@dimen/margin_small"
+		android:layout_marginEnd="@dimen/margin_small"
+		android:textSize="@dimen/text_size_medium"
+		android:gravity="center_vertical"
+		tools:text="This is a name of a contact. It can be quite long."/>
+
+	<TextView
+		android:id="@+id/dateView"
+		android:layout_width="wrap_content"
+		android:layout_height="match_parent"
+		android:layout_marginRight="@dimen/margin_small"
+		android:layout_marginEnd="@dimen/margin_small"
+		android:gravity="center_vertical"
+		android:textColor="@color/no_private_messages"
+		tools:text="Dec 24"/>
+
+	</LinearLayout>
+
+	<View style="@style/Divider.Horizontal"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/briar-android/res/layout/transports_list.xml b/briar-android/res/layout/transports_list.xml
index c1ec632f65..c359d7c1de 100644
--- a/briar-android/res/layout/transports_list.xml
+++ b/briar-android/res/layout/transports_list.xml
@@ -5,10 +5,7 @@
 	android:layout_width="match_parent"
 	android:layout_height="wrap_content">
 
-	<View
-		android:layout_width="match_parent"
-		android:layout_height="1px"
-		android:background="@color/horizontal_border"/>
+	<View style="@style/Divider.Horizontal"/>
 
 	<GridView
 		android:id="@+id/transportsView"
diff --git a/briar-android/res/menu/contact_actions.xml b/briar-android/res/menu/contact_actions.xml
new file mode 100644
index 0000000000..3cce37ad83
--- /dev/null
+++ b/briar-android/res/menu/contact_actions.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:app="http://schemas.android.com/apk/res-auto">
+
+	<item
+		android:id="@+id/action_social_remove_person"
+		android:icon="@drawable/social_remove_person"
+		app:showAsAction="always"
+		android:title="@string/delete_contact"/>
+
+</menu>
\ No newline at end of file
diff --git a/briar-android/res/menu/contact_list_actions.xml b/briar-android/res/menu/contact_list_actions.xml
new file mode 100644
index 0000000000..718200a659
--- /dev/null
+++ b/briar-android/res/menu/contact_list_actions.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:app="http://schemas.android.com/apk/res-auto">
+
+	<item
+		android:id="@+id/action_social_add_person"
+		android:icon="@drawable/social_add_person"
+		app:showAsAction="always"
+		android:title="@string/add_contact_title"/>
+
+</menu>
\ No newline at end of file
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index fe43fd7c25..0a7c7b1f0e 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -126,4 +126,6 @@
     <!-- Dialogs -->
     <string name="dialog_title_lost_password">Lost password</string>
     <string name="dialog_message_lost_password">Password recovery is not possible. Do you wish to delete your user, all contacts, and re-register ?</string>
+    <string name="dialog_title_delete_contact">Confirm Contact Deletion</string>
+    <string name="dialog_message_delete_contact">Are you sure that you want to remove this contact and all messages exchanged with this contact?</string>
 </resources>
diff --git a/briar-android/res/values/styles.xml b/briar-android/res/values/styles.xml
index f40b8b5419..0e0c2c0b94 100644
--- a/briar-android/res/values/styles.xml
+++ b/briar-android/res/values/styles.xml
@@ -33,4 +33,13 @@
         <item name="android:textSize">@dimen/text_size_small</item>
         <item name="android:textColor">@android:color/primary_text_light</item>
     </style>
+
+    <style name="Divider">
+        <item name="android:background">?android:attr/listDivider</item>
+    </style>
+
+    <style name="Divider.Horizontal">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">1px</item>
+    </style>
 </resources>
\ No newline at end of file
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
index fff550fc46..1edbd2d2a0 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListActivity.java
@@ -1,28 +1,20 @@
 package org.briarproject.android.contact;
 
 import android.content.Intent;
-import android.content.res.Resources;
+import android.graphics.PorterDuff;
 import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.View.OnCreateContextMenuListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.ListView;
+import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import org.briarproject.R;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.invitation.AddContactActivity;
-import org.briarproject.android.util.HorizontalBorder;
-import org.briarproject.android.util.ListLoadingProgressBar;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.contact.ContactManager;
@@ -36,43 +28,34 @@ import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.MessageAddedEvent;
-import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.messaging.MessagingManager;
 import org.briarproject.api.messaging.PrivateMessageHeader;
 import org.briarproject.api.plugins.ConnectionRegistry;
 import org.briarproject.api.sync.GroupId;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.Menu.NONE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
-import static android.widget.LinearLayout.VERTICAL;
-import static android.widget.Toast.LENGTH_SHORT;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1;
 
 public class ContactListActivity extends BriarActivity
-implements OnClickListener, OnItemClickListener, OnCreateContextMenuListener,
-EventListener {
+		implements OnCreateContextMenuListener, EventListener {
 
-	private static final int MENU_ITEM_DELETE = 1;
 	private static final Logger LOG =
 			Logger.getLogger(ContactListActivity.class.getName());
 
 	@Inject private ConnectionRegistry connectionRegistry;
 	private TextView empty = null;
 	private ContactListAdapter adapter = null;
-	private ListView list = null;
-	private ListLoadingProgressBar loading = null;
+	private RecyclerView list = null;
+	private ProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile ContactManager contactManager;
@@ -82,47 +65,28 @@ EventListener {
 	@Override
 	public void onCreate(Bundle state) {
 		super.onCreate(state);
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
 
-		empty = new TextView(this);
-		empty.setLayoutParams(MATCH_WRAP_1);
-		empty.setGravity(CENTER);
-		empty.setTextSize(18);
-		empty.setText(R.string.no_contacts);
-		empty.setVisibility(GONE);
-		layout.addView(empty);
+		setContentView(R.layout.activity_contact_list);
 
 		adapter = new ContactListAdapter(this);
-		list = new ListView(this);
-		list.setLayoutParams(MATCH_WRAP_1);
+		list = (RecyclerView) findViewById(R.id.contactList);
+		list.setLayoutManager(new LinearLayoutManager(this));
 		list.setAdapter(adapter);
-		list.setOnItemClickListener(this);
 		list.setOnCreateContextMenuListener(this);
 		list.setVisibility(GONE);
-		layout.addView(list);
 
-		// Show a progress bar while the list is loading
-		loading = new ListLoadingProgressBar(this);
-		layout.addView(loading);
-
-		layout.addView(new HorizontalBorder(this));
+		// Show a notice when there are no contacts
+		empty = (TextView) findViewById(R.id.emptyView);
 
-		LinearLayout footer = new LinearLayout(this);
-		footer.setLayoutParams(MATCH_WRAP);
-		footer.setGravity(CENTER);
-		Resources res = getResources();
-		footer.setBackgroundColor(res.getColor(R.color.button_bar_background));
-		ImageButton addContactButton = new ImageButton(this);
-		addContactButton.setBackgroundResource(0);
-		addContactButton.setImageResource(R.drawable.social_add_person);
-		addContactButton.setOnClickListener(this);
-		footer.addView(addContactButton);
-		layout.addView(footer);
+		// Show a progress bar while the list is loading
+		loading = (ProgressBar) findViewById(R.id.progressBar);
+		loading.setVisibility(VISIBLE);
+	}
 
-		setContentView(layout);
+	@Override
+	public void onPause() {
+		super.onPause();
+		eventBus.removeListener(this);
 	}
 
 	@Override
@@ -132,12 +96,47 @@ EventListener {
 		loadContacts();
 	}
 
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		// Inflate the menu items for use in the action bar
+		MenuInflater inflater = getMenuInflater();
+		inflater.inflate(R.menu.contact_list_actions, menu);
+
+		// adapt icon color to dark action bar
+		menu.findItem(R.id.action_social_add_person).getIcon().setColorFilter(
+				getResources().getColor(R.color.action_bar_text),
+				PorterDuff.Mode.SRC_IN);
+
+		return super.onCreateOptionsMenu(menu);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(final MenuItem item) {
+		// Handle presses on the action bar items
+		switch (item.getItemId()) {
+			case R.id.action_social_add_person:
+				startActivity(new Intent(this, AddContactActivity.class));
+				return true;
+			default:
+				return super.onOptionsItemSelected(item);
+		}
+	}
+
+
 	private void loadContacts() {
-		clearContacts();
+		runOnUiThread(new Runnable() {
+			public void run() {
+				empty.setVisibility(GONE);
+				list.setVisibility(GONE);
+				loading.setVisibility(VISIBLE);
+			}
+		});
 		runOnDbThread(new Runnable() {
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
+					List<ContactListItem> contacts =
+							new ArrayList<ContactListItem>();
 					for (Contact c : contactManager.getContacts()) {
 						try {
 							ContactId id = c.getId();
@@ -145,15 +144,20 @@ EventListener {
 									messagingManager.getConversationId(id);
 							Collection<PrivateMessageHeader> headers =
 									messagingManager.getMessageHeaders(id);
-							displayContact(c, conversation, headers);
+
+							boolean connected =
+									connectionRegistry.isConnected(c.getId());
+							contacts.add(new ContactListItem(c, connected,
+									conversation,
+									headers));
 						} catch (NoSuchContactException e) {
 							// Continue
 						}
 					}
+					displayContacts(contacts);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Full load took " + duration + " ms");
-					hideProgressBar();
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -162,110 +166,19 @@ EventListener {
 		});
 	}
 
-	private void clearContacts() {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				empty.setVisibility(GONE);
-				list.setVisibility(GONE);
-				loading.setVisibility(VISIBLE);
-				adapter.clear();
-				adapter.notifyDataSetChanged();
-			}
-		});
-	}
-
-	private void displayContact(final Contact c, final GroupId conversation,
-			final Collection<PrivateMessageHeader> headers) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				list.setVisibility(VISIBLE);
-				loading.setVisibility(GONE);
-				boolean connected = connectionRegistry.isConnected(c.getId());
-				// Remove the old item, if any
-				ContactListItem item = findItem(c.getId());
-				if (item != null) adapter.remove(item);
-				// Add a new item
-				adapter.add(new ContactListItem(c, connected, conversation,
-						headers));
-				adapter.sort(ContactListItemComparator.INSTANCE);
-				adapter.notifyDataSetChanged();
-			}
-		});
-	}
-
-	private void hideProgressBar() {
+	private void displayContacts(final List<ContactListItem> contacts) {
 		runOnUiThread(new Runnable() {
 			public void run() {
-				if (adapter.isEmpty()) empty.setVisibility(VISIBLE);
-				else list.setVisibility(VISIBLE);
+				if(contacts.size() > 0) {
+					list.setVisibility(VISIBLE);
+					empty.setVisibility(GONE);
+				} else {
+					list.setVisibility(GONE);
+					empty.setVisibility(VISIBLE);
+				}
 				loading.setVisibility(GONE);
-			}
-		});
-	}
-
-	private ContactListItem findItem(ContactId c) {
-		int count = adapter.getCount();
-		for (int i = 0; i < count; i++) {
-			ContactListItem item = adapter.getItem(i);
-			if (item.getContact().getId().equals(c)) return item;
-		}
-		return null; // Not found
-	}
-
-	@Override
-	public void onPause() {
-		super.onPause();
-		eventBus.removeListener(this);
-	}
-
-	public void onClick(View view) {
-		startActivity(new Intent(this, AddContactActivity.class));
-	}
-
-	public void onItemClick(AdapterView<?> parent, View view, int position,
-			long id) {
-		ContactListItem item = adapter.getItem(position);
-		ContactId contactId = item.getContact().getId();
-		String contactName = item.getContact().getAuthor().getName();
-		GroupId groupId = item.getConversationId();
-		AuthorId localAuthorId = item.getContact().getLocalAuthorId();
-		Intent i = new Intent(this, ConversationActivity.class);
-		i.putExtra("briar.CONTACT_ID", contactId.getInt());
-		i.putExtra("briar.CONTACT_NAME", contactName);
-		i.putExtra("briar.GROUP_ID", groupId.getBytes());
-		i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
-		startActivity(i);
-	}
-
-	@Override
-	public void onCreateContextMenu(ContextMenu menu, View view,
-			ContextMenu.ContextMenuInfo info) {
-		String delete = getString(R.string.delete_contact);
-		menu.add(NONE, MENU_ITEM_DELETE, NONE, delete);
-	}
-
-	@Override
-	public boolean onContextItemSelected(MenuItem menuItem) {
-		if (menuItem.getItemId() == MENU_ITEM_DELETE) {
-			ContextMenuInfo info = menuItem.getMenuInfo();
-			int position = ((AdapterContextMenuInfo) info).position;
-			ContactListItem item = adapter.getItem(position);
-			removeContact(item.getContact().getId());
-			String deleted = getString(R.string.contact_deleted_toast);
-			Toast.makeText(this, deleted, LENGTH_SHORT).show();
-		}
-		return true;
-	}
 
-	private void removeContact(final ContactId c) {
-		runOnDbThread(new Runnable() {
-			public void run() {
-				try {
-					contactManager.removeContact(c);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
+				adapter.addAll(contacts);
 			}
 		});
 	}
@@ -314,7 +227,7 @@ EventListener {
 			final Collection<PrivateMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
-				ContactListItem item = findItem(c);
+				ContactListItem item = adapter.findItem(c);
 				if (item != null) {
 					item.setHeaders(headers);
 					adapter.notifyDataSetChanged();
@@ -326,10 +239,10 @@ EventListener {
 	private void removeItem(final ContactId c) {
 		runOnUiThread(new Runnable() {
 			public void run() {
-				ContactListItem item = findItem(c);
+				ContactListItem item = adapter.findItem(c);
 				if (item != null) {
 					adapter.remove(item);
-					adapter.notifyDataSetChanged();
+
 					if (adapter.isEmpty()) {
 						empty.setVisibility(VISIBLE);
 						list.setVisibility(GONE);
@@ -342,7 +255,7 @@ EventListener {
 	private void setConnected(final ContactId c, final boolean connected) {
 		runOnUiThread(new Runnable() {
 			public void run() {
-				ContactListItem item = findItem(c);
+				ContactListItem item = adapter.findItem(c);
 				if (item != null) {
 					item.setConnected(connected);
 					adapter.notifyDataSetChanged();
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
index 1acb52435d..7e511ea9a4 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
@@ -1,80 +1,194 @@
 package org.briarproject.android.contact;
 
-import static android.text.TextUtils.TruncateAt.END;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1;
-
-import java.util.ArrayList;
-
-import org.briarproject.R;
-import org.briarproject.android.util.LayoutUtils;
-
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
+import android.support.v7.util.SortedList;
+import android.support.v7.widget.RecyclerView;
 import android.text.format.DateUtils;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
-class ContactListAdapter extends ArrayAdapter<ContactListItem> {
+import org.briarproject.R;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.identity.AuthorId;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.List;
+
+public class ContactListAdapter
+		extends RecyclerView.Adapter<ContactListAdapter.ContactHolder> {
 
-	private final int pad;
+	private SortedList<ContactListItem> contacts =
+			new SortedList<ContactListItem>(ContactListItem.class,
+					new SortedList.Callback<ContactListItem>() {
+						@Override
+						public void onInserted(int position, int count) {
+							notifyItemRangeInserted(position, count);
+						}
 
-	ContactListAdapter(Context ctx) {
-		super(ctx, android.R.layout.simple_expandable_list_item_1,
-				new ArrayList<ContactListItem>());
-		pad = LayoutUtils.getPadding(ctx);
+						@Override
+						public void onChanged(int position, int count) {
+							notifyItemRangeChanged(position, count);
+						}
+
+						@Override
+						public void onMoved(int fromPosition, int toPosition) {
+							notifyItemMoved(fromPosition, toPosition);
+						}
+
+						@Override
+						public void onRemoved(int position, int count) {
+							notifyItemRangeRemoved(position, count);
+						}
+
+						@Override
+						public int compare(ContactListItem c1,
+								ContactListItem c2) {
+							return (int) (c1.getTimestamp() -
+									c2.getTimestamp());
+						}
+
+						@Override
+						public boolean areItemsTheSame(ContactListItem c1,
+								ContactListItem c2) {
+							return c1.getContact().getId().equals(c2.getContact().getId());
+						}
+
+						@Override
+						public boolean areContentsTheSame(ContactListItem c1,
+								ContactListItem c2) {
+							return c1.equals(c2);
+						}
+					});
+	private Context ctx;
+
+	public ContactListAdapter(Context context) {
+		ctx = context;
 	}
 
 	@Override
-	public View getView(int position, View convertView, ViewGroup parent) {
-		ContactListItem item = getItem(position);
-		Context ctx = getContext();
+	public ContactHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
+		View v = LayoutInflater.from(viewGroup.getContext())
+				.inflate(R.layout.list_item_contact, viewGroup, false);
+
+		return new ContactHolder(v);
+	}
+
+	@Override
+	public void onBindViewHolder(final ContactHolder ui, final int position) {
+		final ContactListItem item = getItem(position);
 		Resources res = ctx.getResources();
 
-		LinearLayout layout = new LinearLayout(ctx);
-		layout.setOrientation(HORIZONTAL);
-		layout.setGravity(CENTER_VERTICAL);
 		int unread = item.getUnreadCount();
-		if (unread > 0)
-			layout.setBackgroundColor(res.getColor(R.color.unread_background));
-
-		ImageView bulb = new ImageView(ctx);
-		bulb.setPadding(pad, pad, pad, pad);
-		if (item.isConnected())
-			bulb.setImageResource(R.drawable.contact_connected);
-		else bulb.setImageResource(R.drawable.contact_disconnected);
-		layout.addView(bulb);
-
-		TextView name = new TextView(ctx);
-		name.setLayoutParams(WRAP_WRAP_1);
-		name.setTextSize(18);
-		name.setSingleLine();
-		name.setEllipsize(END);
-		name.setPadding(0, pad, pad, pad);
+		if (unread > 0) {
+			ui.layout.setBackgroundColor(
+					res.getColor(R.color.unread_background));
+		}
+
+		if (item.isConnected()) {
+			ui.bulb.setImageResource(R.drawable.contact_connected);
+		} else {
+			ui.bulb.setImageResource(R.drawable.contact_disconnected);
+		}
+
 		String contactName = item.getContact().getAuthor().getName();
-		if (unread > 0) name.setText(contactName + " (" + unread + ")");
-		else name.setText(contactName);
-		layout.addView(name);
+		if (unread > 0) {
+			ui.name.setText(contactName + " (" + unread + ")");
+		} else {
+			ui.name.setText(contactName);
+		}
 
 		if (item.isEmpty()) {
-			TextView noMessages = new TextView(ctx);
-			noMessages.setPadding(pad, pad, pad, pad);
-			noMessages.setTextColor(res.getColor(R.color.no_private_messages));
-			noMessages.setText(R.string.no_private_messages);
-			layout.addView(noMessages);
+			ui.date.setText(R.string.no_private_messages);
 		} else {
-			TextView date = new TextView(ctx);
-			date.setPadding(pad, pad, pad, pad);
 			long timestamp = item.getTimestamp();
-			date.setText(DateUtils.getRelativeTimeSpanString(ctx, timestamp));
-			layout.addView(date);
+			ui.date.setText(
+					DateUtils.getRelativeTimeSpanString(ctx, timestamp));
 		}
 
-		return layout;
+		ui.layout.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				ContactId contactId = item.getContact().getId();
+				String contactName = item.getContact().getAuthor().getName();
+				GroupId groupId = item.getConversationId();
+				AuthorId localAuthorId = item.getContact().getLocalAuthorId();
+
+				Intent i = new Intent(ctx, ConversationActivity.class);
+				i.putExtra("briar.CONTACT_ID", contactId.getInt());
+				i.putExtra("briar.CONTACT_NAME", contactName);
+				i.putExtra("briar.GROUP_ID", groupId.getBytes());
+				i.putExtra("briar.LOCAL_AUTHOR_ID", localAuthorId.getBytes());
+
+				ctx.startActivity(i);
+			}
+		});
+	}
+
+	@Override
+	public int getItemCount() {
+		return contacts == null ? 0 : contacts.size();
+	}
+
+	public boolean isEmpty() {
+		return contacts == null || contacts.size() == 0;
+	}
+
+	public ContactListItem getItem(int position) {
+		if (position == -1 || contacts.size() <= position) {
+			return null; // Not found
+		}
+		return contacts.get(position);
+	}
+
+	public ContactListItem findItem(ContactId c) {
+		int count = getItemCount();
+		for (int i = 0; i < count; i++) {
+			ContactListItem item = getItem(i);
+			if (item.getContact().getId().equals(c)) return item;
+		}
+		return null; // Not found
+	}
+
+	public void addAll(final List<ContactListItem> contacts) {
+		this.contacts.addAll(contacts);
+	}
+
+	public void add(final ContactListItem contact) {
+		this.contacts.add(contact);
+	}
+
+	public void remove(final ContactListItem contact) {
+		this.contacts.remove(contact);
+	}
+
+	public void clear() {
+		contacts.beginBatchedUpdates();
+
+		while(contacts.size() != 0) {
+			contacts.removeItemAt(0);
+		}
+
+		contacts.endBatchedUpdates();
+	}
+
+	public static class ContactHolder extends RecyclerView.ViewHolder {
+		public ViewGroup layout;
+		public ImageView bulb;
+		public TextView name;
+		public TextView date;
+
+		public ContactHolder(View v) {
+			super(v);
+
+			layout = (ViewGroup) v;
+			bulb = (ImageView) v.findViewById(R.id.bulbView);
+			name = (TextView) v.findViewById(R.id.nameView);
+			date = (TextView) v.findViewById(R.id.dateView);
+		}
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index ff90470fea..98dcd179f8 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -1,10 +1,16 @@
 package org.briarproject.android.contact;
 
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -15,6 +21,7 @@ import android.widget.ImageButton;
 import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import org.briarproject.R;
 import org.briarproject.android.BriarActivity;
@@ -66,6 +73,7 @@ import javax.inject.Inject;
 
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
+import static android.widget.Toast.LENGTH_SHORT;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static org.briarproject.android.contact.ReadPrivateMessageActivity.RESULT_PREV_NEXT;
@@ -161,6 +169,33 @@ implements EventListener, OnClickListener, OnItemClickListener {
 		loadHeaders();
 	}
 
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		// Inflate the menu items for use in the action bar
+		MenuInflater inflater = getMenuInflater();
+		inflater.inflate(R.menu.contact_actions, menu);
+
+		// adapt icon color to dark action bar
+		menu.findItem(R.id.action_social_remove_person).getIcon().setColorFilter(
+				getResources().getColor(R.color.action_bar_text),
+				PorterDuff.Mode.SRC_IN);
+
+		return super.onCreateOptionsMenu(menu);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(final MenuItem item) {
+		// Handle presses on the action bar items
+		switch (item.getItemId()) {
+			case R.id.action_social_remove_person:
+				askToRemoveContact();
+
+				return true;
+			default:
+				return super.onOptionsItemSelected(item);
+		}
+	}
+
 	private void loadContactAndGroup() {
 		runOnDbThread(new Runnable() {
 			public void run() {
@@ -478,4 +513,59 @@ implements EventListener, OnClickListener, OnItemClickListener {
 		i.putExtra("briar.POSITION", position);
 		startActivityForResult(i, REQUEST_READ);
 	}
+
+	private void askToRemoveContact() {
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				DialogInterface.OnClickListener okListener =
+						new DialogInterface.OnClickListener() {
+							@Override
+							public void onClick(DialogInterface dialog,
+									int which) {
+								removeContact();
+							}
+						};
+
+				AlertDialog.Builder builder =
+						new AlertDialog.Builder(ConversationActivity.this);
+				builder.setTitle(
+						getString(R.string.dialog_title_delete_contact));
+				builder.setMessage(
+						getString(R.string.dialog_message_delete_contact));
+				builder.setPositiveButton(android.R.string.ok, okListener);
+				builder.setNegativeButton(android.R.string.cancel, null);
+				builder.show();
+			}
+		});
+	}
+
+	private void removeContact() {
+		runOnDbThread(new Runnable() {
+			public void run() {
+				try {
+					contactManager.removeContact(contactId);
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				} finally {
+					finishAfterContactRemoved();
+				}
+			}
+		});
+	}
+
+	private void finishAfterContactRemoved() {
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				String deleted = getString(R.string.contact_deleted_toast);
+				Toast.makeText(ConversationActivity.this, deleted, LENGTH_SHORT)
+						.show();
+
+				finish();
+			}
+		});
+	}
+
 }
-- 
GitLab