From 4e5366509d9f913f22b58f1b61e8fd843d458797 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Sat, 23 Mar 2013 14:30:59 +0000
Subject: [PATCH] Android UI for blogs (restricted groups).

---
 briar-android/AndroidManifest.xml             |   6 +-
 .../res/drawable-hdpi/social_blog.png         | Bin 0 -> 948 bytes
 .../res/drawable-hdpi/social_new_blog.png     | Bin 0 -> 1202 bytes
 .../res/drawable-mdpi/social_blog.png         | Bin 0 -> 558 bytes
 .../res/drawable-mdpi/social_new_blog.png     | Bin 0 -> 752 bytes
 .../res/drawable-xhdpi/social_blog.png        | Bin 0 -> 918 bytes
 .../res/drawable-xhdpi/social_new_blog.png    | Bin 0 -> 1207 bytes
 briar-android/res/values/color.xml            |   1 +
 briar-android/res/values/strings.xml          |   3 +-
 .../sf/briar/android/HomeScreenActivity.java  |  19 ++-
 .../briar/android/groups/GroupActivity.java   |   9 +-
 .../android/groups/GroupListActivity.java     | 112 +++++++++++++++---
 .../groups/WriteGroupMessageActivity.java     |   4 +
 .../sf/briar/api/db/DatabaseComponent.java    |   2 +-
 .../api/db/event/GroupMessageAddedEvent.java  |  12 +-
 .../db/event/SubscriptionRemovedEvent.java    |  12 +-
 .../src/net/sf/briar/api/messaging/Group.java |   5 +
 .../sf/briar/db/DatabaseComponentImpl.java    |  17 ++-
 .../src/net/sf/briar/db/JdbcDatabase.java     |   8 +-
 .../briar/messaging/MessageFactoryImpl.java   |   8 +-
 .../net/sf/briar/messaging/MessageReader.java |   2 +-
 .../briar/messaging/MessageVerifierImpl.java  |   2 +-
 .../sf/briar/messaging/PacketWriterImpl.java  |   5 +-
 .../sf/briar/db/DatabaseComponentTest.java    |   6 +-
 24 files changed, 168 insertions(+), 65 deletions(-)
 create mode 100644 briar-android/res/drawable-hdpi/social_blog.png
 create mode 100644 briar-android/res/drawable-hdpi/social_new_blog.png
 create mode 100644 briar-android/res/drawable-mdpi/social_blog.png
 create mode 100644 briar-android/res/drawable-mdpi/social_new_blog.png
 create mode 100644 briar-android/res/drawable-xhdpi/social_blog.png
 create mode 100644 briar-android/res/drawable-xhdpi/social_new_blog.png

diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index fc8fcd5289..ad48f4aea1 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -42,15 +42,15 @@
 		</activity>
 		<activity
 			android:name=".android.groups.GroupActivity"
-			android:label="@string/groups_title" >
+			android:label="@string/app_name" >
 		</activity>
 		<activity
 			android:name=".android.groups.GroupListActivity"
-			android:label="@string/groups_title" >
+			android:label="@string/app_name" >
 		</activity>
 		<activity
 			android:name=".android.groups.ReadGroupMessageActivity"
-			android:label="@string/groups_title" >
+			android:label="@string/app_name" >
 		</activity>
 		<activity
 			android:name=".android.groups.WriteGroupMessageActivity"
diff --git a/briar-android/res/drawable-hdpi/social_blog.png b/briar-android/res/drawable-hdpi/social_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..dfafb709b7322d9a0ff679c975e1835ec1499966
GIT binary patch
literal 948
zcmV;l155mgP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px&Zb?KzRA}Dqm`hI+Q5c4w>9jzRDnu?SD5)5u2}Vr_M)$gRr->W?nJX9m1rrx0
zZj43}7Am5kSU`f;A~%_-n|G3vFQ+g_$7(WfGD$O>9=_*%*B;1~D_5>uxpK8nLCSUA
zz!9JVlz|Y~0XBg;@Eurh2S739x?4aj!$aqNWS%-O1uXn)0A=8p=e-Nm0D6ECeSQJF
z6jUQCfH38{NqHbmI5zYQ0~ZCq0sL$yz!e!)(02-Y0zHY*ZcfE|*AJWlN<gh$NqiHS
z16F`<O5QG@7Z}uO_sPhT;|UzV0<Z-<Xl23&Ej)~pU`_(3bn-jS-xCk50gr&?zZpVl
z6f0pr0<$WuqsI6K&<TtItH6(c2>?@GSAiK|K-DR5JRSg5U`ZbNs{q}KeVUY3SKGjA
z#s6`~6M^0h18-C8bKo2}30zVqPO4D6&*pU&xS>Q29GGq3Ue+GCtE!V!nWFQ#0-OUT
z1op)wZ=%ntU{zC{O0uJtCBTGEJlLaojmTSpO0Ewg0FD`m0RjBX3SiP{Oo1^xFv(jM
zL}!z*S`=u-fhg$nhb%ksrs8)6cqe0vo_zvml;~<=)FN=f9Ktar{8knKJ-|~vujKAG
z8rGH-^GCH`Vo;>YQ}TFXTitlfnXwAmr<Mi4do`W7N%L9&=GC}598W~RkmEU5b#?5r
z<FymOvn&A8jKdq6mqr!;Zhll0b~`3tDgwmu!l(Uo=s)emLyFmT8RCY<JaF29NB|;F
zcr;X2?Qe>itN=pbj+#;xIInlh2BN0kkc`}MlknKo9!1mKrn3O(18zHwC)7W#>U5Wk
zVcn|lyM;%rl6%<X&1~B7qL9+~4&b_swnNz#a22?0LSxPt5osK;su?>%T_DhEfWaoo
zoIs2#?h~yDpy5DOJl|h2%`j}T?mz&(u4^Gm>aaMI>R02fP@(1On+KpP3xHska@tTl
z+u45A7*_xec@p_gZ%g(Cu-Dp1N$RTKK*yee&3D>6tp->Fo|qd5x5350ea~;?KC?FR
z{GjhOkWmw_9Oz;TT~q;FbCR>DFnMSi8cO<-$$`3O-$4&RJqv&sc&_p|uHkK3)8@7(
zU#iX(OOl*Zo_&YSj1}oZpydFGz5tI?Tt$wUlk`ocp-Qy7Zk;w=6z9s7D_5@nPrm_Q
W(eaa!`oEn30000<MNUMnLSTX!U8$)6

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-hdpi/social_new_blog.png b/briar-android/res/drawable-hdpi/social_new_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad2c5f31a36616193928b7cb7239a15f6b9b52ed
GIT binary patch
literal 1202
zcmV;j1Wo&iP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*e~
z4jUW6*Pq(}00c5gL_t(&-tCx8j}%oDhM%hbV0xs5i7=o8k_KWl!JsLE(Tyuz=*qZ}
zgpL2fpTHmRAGlJ(h81Bki3<}q#>x;$MEMYOY#7E7k%pP>v8$TRTglDIEvA^7nrV_g
zNhO`z^>N;N&U@Z-4@_)gr7Xx<p9b~-ZJ-6zfFaNadcc3c>No(X=d6DQq;kCGtS9E`
z0hfWraRbl-{`aiAfJVS>;E;YV09OTSv|RvdIqRntfg<TQ(lrO16!<mZ@lFDGM^1&h
zC)5?_%A9sNlxl4sa2#j=-JK%wC%`RW8F(P_P62y?S?%_WoNPFezyTNn1K@m>gbzwQ
z+Yp$;z^mH%q4R$hp+~@Xz|wZ6P!UT-*uQ`qDy>J1^CMsva12-h9*z?LOnF@at^xa1
zodPGq0nh>NDk9qoU|P9PPHA;*9r#W8|FRQ_Kx=cr%>wT!&4I(fTT<ez3Z>5|UatWk
zipYTjW*zvd>Ii(Us*_cjy7RjYybhcau=|F*nf;>*)-lzoq3?F91aL|_9&8|9hZL<q
zCD#Wc01g@u`vu@}RRB&q!W0<C14G`HK<vs%t2+YPc0h#s{b!X*+*kfC1Ha4Jy63sT
zX(gs|oVo+NX*S`Y2tTL-z;572UB4>a*VU{oDd%6(^O-}5Do?``iFK**F{j50^`34O
z0RE8Zq&ecX2;7!%HJwN#zyT+6uJxqYEhlQP06$d$ph!Esrhe&&^55l0TWL2md}#|H
zP89ByQRt#dd_Xz7Do5PZxD6b2Kx6<CPkM}0R_&SMT2%mQz*&h>2Y5qkO9n(&+K{!}
zX-<0d^^Up`w<}cum;uf>!c)_SJKEj5#<6MD_ot;ts*?Mn;mwWBwijW}dK36SPTQtz
z0K5ylZBpZwaUxMWVy$bwThjo6tp+fgL*@*`3FUoe%K|WRK(#&3FB>te<=j^afKPQT
zh=vpvr&ImcM60IMa_xZ!z*H3gf~S<zk@DI0_AAD@5O~2u<f7A&QUJmNhnRb2ZJz<1
zdKxz0ZV$J5F7yca0f;<@^{h;O?KvaQnB!#PIneJlAQLw#Q50o;QV6WXaXi=z05qrq
zc+VkcU1>6J1PzhCVK~t9ym!_Epl2fVg#_+P;Frw;NP$@8@r0VUE9y4aJ$&gnBbJPu
zmp$*DGd)(Kfq<=o%>rp$h&=a!?>D%orHa%uDYfVk&ZfC<)stqaa~>%Tpopyk-xi!+
zT-eH~M96b);|QQ{8pX;+i=`}zqT?cTVg#}Ye5y8OUcHkQ$6g%A3tP#7&Di_ENB9T7
zYa;Q-o-ApqGVVBlzjcrqm<WVAK!q9x^i2fnT4$#LTm&w8N@WW;Cn5W$jF44oaU3Te
zH7AN9m$<_?j)%`%6$+oF$V_x#0>H0L(>e%kIQFTJA%Fz<S=Hzv6B~1T0{o391E@)b
Qs{jB107*qoM6N<$f_H`+>;M1&

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-mdpi/social_blog.png b/briar-android/res/drawable-mdpi/social_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..22a330fec002129d3251a169101e84b3ef9b7be7
GIT binary patch
literal 558
zcmV+}0@3}6P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px$=t)FDR9M69*3D{DVGsu3Cyk<lMq6#%XscDMS`<V?L8)DP0j^xS^OD>Og5HF<
zQ$eICSP)4I5v<goh*YWRaWjG8kR~*#=pyebGxPntGxN@O!U!Xb@Q+dH5xa#6)KK6%
zKH&=*SpC}s?qQ>gzd#jjEaKTP1gbq^*V3A?AX}8kAB}ZCqB=WTf%Eu)R@gPvF@>2_
zjm{Zg@wh~CC<6U(2G_AWk@<y(TeNQ5E$D|eyutxYrt{8)Hijlp#~d!;bWFrX^gE-0
zpE#KWdJ1obC2$vqaR>)PaC5j67iQ6|Vja_A?+v@JFvohtes}S0hHh@)c1c68@iy5D
z!&cxb-bJ4qQQq+s-xC#CEVbieB(@m>Z4NpGokPl4z}biu_=ZQN=~zgUaevSXY&Fk~
z5aZMq{a(Z6bpA>g;cjaT=W#QHxE#KZ*dHQ=<9M0&jE8tTZ$ons5yBnJMwYW-ckrZ?
zNIlsr(cVf)H`^j`1^bdtDq+v3HSZ(KHcphrvQyp3K?$_Gh_q6=XgOs%k^HT+w>Bt&
zY8N3EA;KL)F9I(@-9@^59Z%Dm>F^i$ocy)4uQezEcz~sNdY8h^n2AzXOO>fd3-x=B
whxr`WaV&oC!t)fH!jUwx&C$Q#5&m2J0fdHZBA-)gRsaA107*qoM6N<$g4gH$;Q#;t

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-mdpi/social_new_blog.png b/briar-android/res/drawable-mdpi/social_new_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..039e5f8537e4480d6ce1e247862cd8a18908e452
GIT binary patch
literal 752
zcmV<M0uTL(P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*e~
z4jeYiNmXe800MAHL_t(o!{wIEY7|irg}+YcN5xE>NXC_kMltH3A{S9m;;aR?g5c7P
zh_B$r$8akM@g*d?L_0{(U_fLt5FsOp8j&Q%nRas;ic8Og?&+9?2YOMr@6V~KQ*|%=
z?+85m4loLofEf4*d<DJ%b)dQ51RevsDf40=1X{o%Fjo|T(6eut@jelZJ;En6@0X%e
zXap_-Uw}>7C7=R~1Cu5i$-3{rE01JP1opx?;3hC&$m{?wJESgi3iiS}@D3OT#>^fU
zq>Y{lRDddQ2{@~Y*j2tQ>cBQ|+6eRv@S#@%4}s&rF<?Z3s{&VbpcP#c*a9YGACjF(
zn0=o8CuL4sTDb+>^K|nb_-O1}uMxNod{Un43UAr`A5ugXy>wibGi?cUHE$IpoA{^!
z=k+fJegHFGb<|8{JkJ|}PW4=u7{@#0dmV6Q&qj)HGnL^qa9cuL(byVrR3Zg92`rd3
zWr;WG4Xb%X2=D-yl9yAm6TJ4wSB%|IN&`<fnFw414jXL*vZu|Q&+@Vbobt*tiRf5f
z0<9Eb2Hrs{#?w(VzG>E$@)8JBgcwVN`vRZ98>u@shi?J1X3m7hV_?IKm(054HpMwN
z;+!jI5#bA9S*>?jw#B4E9eR<eD1~_K_&)H&IhT6#_IDsQ>v?Std280%C)&38w`Rr%
z)IrHYpc9&1-h~Z)Y0tTKmJ}3?77#~K6c_O#>I&!FFmP94PlQ@kQ(N#HUy7n=zQ15^
z2X!+JnTzX)9KB+k4pk|I6W9Qrdij4O@jml<Oe>EFyFz*X?WHBrz|KL5Fc6X8pa={W
i*$47qDa#Y>pW`pm9GgjZFSo7$0000<MNUMnLSTX-zB+OM

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-xhdpi/social_blog.png b/briar-android/res/drawable-xhdpi/social_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..951a5d3f67822aadfe1d1401e4d348e929206d07
GIT binary patch
literal 918
zcmV;H18Mw;P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px&P)S5VRCwC$nM+R-Q5?m8l=sUNA;m|rkf5oLg^3$uT)E*35Ka65el7QgFTlbT
zi7TTqnphVi1OY*yC17m;TNnH%X~^7rdxz<rf!>oeX=d)c&Yb`GpL+*9JUl!+JUl!+
zJUl!+IuBhDj=2ep0~0_N7y$-=I&cIW0u^8f*p>fPpmA9Ucop$lt3V0Z6rxgr9*5T|
z$S)w{Be2~`1cZ@M1KtAbNfFQ;;h0A;zkoZyZD0fV+i3&@=m+irz2Xth3^R%ezLeSx
z9R5ID9$*L<mF_SO<fKd3pbjj^xl>7iEyjQ;U>dk)aonPqW$H@67ByfC_y#NkC!!A1
zwP(c>eqVF~&XTbXd=&%C8OGlNj)lNWK|p|iz?vA|1Td%>n{THQk|H3$fv90vh|nov
z2iQ*&0bO$AIba5u6j|4$&TV7zvAk`aCw!MOO0)|UfMQdujWhet0?!OB^0kyuVhVU6
zecptuJkUdtce#b6w<j{6(Y&x8;O9k4f?12Cw`VAaN#I9ZvDtMLo)kqa8)|vWV2pX-
zOB@7b5^(+u@Vo^NSrRpb;fgHGq(T9QQj=woc%OygnfiN0W{axU_$jINfM39hgqiX=
zvj0=yk0$ePh}0j1>>H34yzN>6o4|Xi)0!dsx03Ws{e2s_uejGiIo2rw2W?1tcSX((
zMQrX@s3{A4K2I)i6@^Vn&(z<mq5@UN*iSnF!Hq`k?=^A#u*H?$^OQjx1ayldKbCqv
zk<QSF(BFqO57Vz8FAIEd-36L2K7S@p6wohgEs1+yRm?N`6my3)Avp{~(oLKOp@IaO
zjAhtq0Pi&Cy{_0^7G<ekgwrIL1?E~9H>bF{4apK=C~D59>iOfY37EGW8|F1D8fB@b
z>AQ;U6Rru!SdPsrY8p*VtD<o#O28Jym}*)T!bZ|gKwLFlRc!A|I{_t9il_wCEyt=N
zZqCx|RNippnt%n%v0;;yF-`5N%x+Y%{m?Z56;8k1nXssNm?_P1RZDZMB;f(8z#Bz5
z)McOU<L0#HybVip+(~LKP~mi)KHt>pN>cN>Ir<IFYLU(`Z9Svy1Oy8ftF-<py9;=t
s*}tjS9>p^}JUl!+JUl!+JUqhjA1ijp!(I^8WB>pF07*qoM6N<$f{omiMF0Q*

literal 0
HcmV?d00001

diff --git a/briar-android/res/drawable-xhdpi/social_new_blog.png b/briar-android/res/drawable-xhdpi/social_new_blog.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee25de145dbcde7cb2f4ce316103adf866ee287e
GIT binary patch
literal 1207
zcmV;o1W5adP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*e~
z4jLqGs)MHh00cKlL_t(|+U=T8ZxdG(#ea7Gk^ps@DCr+Vf}jxEE?Ui|s#tZys=KI_
z_yDZ=04&(^4UiCBSNQ@gx<W!iVu}z{gsP=Pl!Sx?2RTjCI`Oc`v9Q4JJwL}|&p2}=
zOVP~u&Ac=Bo_p?fAVY=>84fUVmUEv1<G=(^01gAgKo$5O*aS9!HDFzTZvj!S5OA@@
zH5Y*eU|B>Z8vQY>Ijv8PjC;W9K_Z|L8QZ`w!1JUL&}TUpw3+DBz-Pb`@b5t*poSsf
zb6`Lk(RIPJiQon0ZcX9KQh9(8;E1ZjI54Ry;e#qLueB3NfG@^?W55jXk;nILN-PtX
z0>0P=R)ELA6JSTt;kw5uX~N626Ywq>&w)o0z)8pT$AO9n><I#D*ae<R@FsvmmTQaM
zh=jfl-KVT*7!?t=NLT}2Cy9WZ9()ow0Zb{ZtIBg<n_SV`wrRqjN~5k;foWj2&epcm
z`=0{7bCk#%N};Yrz>li)E)=w(uN2;;CY;_Yh4~4~i|GgcPMZ@fcsRXRj&zs;{)*c+
z$7O}56cJAxxxC^K#v<@AP6F~Vul++48gfg~&<IC0m`OwgY$_*93h_Y?!E@F34RwpA
z(s;jH^MDt?Q<<64KD_@q;2(?UUs9-l+2Gu;O7Lo@BVZZ0t32Iyc>iXco~ypE0$&)O
z>5#tLQ3A>_IK8t9=g452hYZnF03O8Q3)*dkT~5zc-?tP6ri$@8=>*gswAK2)E!A%{
zTp5TX4f;H<Jq~=MeBM!Ih+3%cqn6DK8OSRDzjnF`)ZcvW9p5mGeXMm$>iwai&loiH
z4$nk#BaEn;bkqn<%h2RK%}xZ|wygWH;dn`rWqJ`Eb%F)pd=u-OH$2>uyhJ0+TGlhw
z{P9i`Fz2z>oIz8bS|ZETj;|YzPjs4qyysd)Lr!DKX_GZhL<;y~woN&0GGT|4PC&bI
zddqNpFzEy=kTSRksCukbwOHIqPq8y;L)-t~z-5HyRp*<*yrEecv*fNx?2Z_Yzo#WZ
z5RAxPM?g6Y!}WGXzy^E2-MMhnvYBI+?`?UCW21YV0j>a-f$!tcfJNYELpoG-&i3Qx
zjAh-(QykYU9cF(k&0Vv-zy^DB`eI$FTTss1dh|~$(;}N-`f5g0_lbpo+Q4Fw=6}l0
z0pB_%PP9ogV($i9K_p@HMG3f;lrq@!$O!0xJyhzt%H1Ssz`hX#!4P{h!kk5CirRPt
zd=Lb|Nry0(!!TS)1p#t+m-L*Gfq*=32drmhj7%5+?f}=*LO@=9fr)^e-u_PAer$Uh
zWN+w7S_t?L_(KlQ6ak}(l-e9&&5`oUX(HeSaMf|m*GiKL@Eh<`6aFL}1cYH2xs*K!
zg8K7O7>2vPIhJ<h_A4@(5y}Y22spUt?}0t^$t+c9VQk(D1Z)Do%MGrOAwvcqyaDgW
V1f(=2CaM4c002ovPDHLkV1k|fEA0RP

literal 0
HcmV?d00001

diff --git a/briar-android/res/values/color.xml b/briar-android/res/values/color.xml
index 6252b617f5..986454bcf2 100644
--- a/briar-android/res/values/color.xml
+++ b/briar-android/res/values/color.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
+    <color name="home_screen_background">#FFFFFF</color>
     <color name="content_background">#FFFFFF</color>
     <color name="unread_background">#FFFFFF</color>
 	<color name="horizontal_border">#CCCCCC</color>
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 14258e0471..5881c29be0 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -44,7 +44,8 @@
 	<string name="format_to">To: %1$s</string>
 	<string name="compose_message_title">New Message</string>
 	<string name="to">To:</string>
-	<string name="groups_title">Groups</string>
 	<string name="anonymous">(Anonymous)</string>
+	<string name="groups_title">Groups</string>
 	<string name="compose_group_title">New Post</string>
+	<string name="blogs_title">Blogs</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 02cea07efb..3cf5159051 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -89,8 +89,12 @@ public class HomeScreenActivity extends BriarActivity {
 			groupsButton.setText(R.string.groups_button);
 			groupsButton.setOnClickListener(new OnClickListener() {
 				public void onClick(View view) {
-					startActivity(new Intent(HomeScreenActivity.this,
-							GroupListActivity.class));
+					Intent i = new Intent(HomeScreenActivity.this,
+							GroupListActivity.class);
+					i.putExtra("net.sf.briar.RESTRICTED", false);
+					i.putExtra("net.sf.briar.TITLE",
+							getResources().getString(R.string.groups_title));
+					startActivity(i);
 				}
 			});
 			buttons.add(groupsButton);
@@ -99,11 +103,16 @@ public class HomeScreenActivity extends BriarActivity {
 			blogsButton.setLayoutParams(matchParent);
 			blogsButton.setBackgroundResource(0);
 			blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
-					R.drawable.social_share, 0, 0);
+					R.drawable.social_blog, 0, 0);
 			blogsButton.setText(R.string.blogs_button);
 			blogsButton.setOnClickListener(new OnClickListener() {
 				public void onClick(View view) {
-					// FIXME: Hook this button up to an activity
+					Intent i = new Intent(HomeScreenActivity.this,
+							GroupListActivity.class);
+					i.putExtra("net.sf.briar.RESTRICTED", true);
+					i.putExtra("net.sf.briar.TITLE",
+							getResources().getString(R.string.blogs_title));
+					startActivity(i);
 				}
 			});
 			buttons.add(blogsButton);
@@ -138,6 +147,8 @@ public class HomeScreenActivity extends BriarActivity {
 			grid.setLayoutParams(matchParent);
 			grid.setGravity(CENTER);
 			grid.setPadding(5, 5, 5, 5);
+			grid.setBackgroundColor(getResources().getColor(
+					R.color.home_screen_background));
 			grid.setNumColumns(2);
 			grid.setAdapter(new BaseAdapter() {
 
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
index deff171b85..43af87cf9d 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
@@ -51,6 +51,7 @@ OnClickListener, OnItemClickListener {
 	private final BriarServiceConnection serviceConnection =
 			new BriarServiceConnection();
 
+	private boolean restricted = false;
 	private String groupName = null;
 	private GroupAdapter adapter = null;
 	private ListView list = null;
@@ -65,6 +66,7 @@ OnClickListener, OnItemClickListener {
 		super.onCreate(null);
 
 		Intent i = getIntent();
+		restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
 		byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
 		if(id == null) throw new IllegalStateException();
 		groupId = new GroupId(id);
@@ -194,7 +196,8 @@ OnClickListener, OnItemClickListener {
 
 	public void eventOccurred(DatabaseEvent e) {
 		if(e instanceof GroupMessageAddedEvent) {
-			if(((GroupMessageAddedEvent) e).getGroupId().equals(groupId)) {
+			GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
+			if(g.getGroup().getId().equals(groupId)) {
 				if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
 				loadHeaders();
 			}
@@ -205,7 +208,8 @@ OnClickListener, OnItemClickListener {
 			if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
 			loadHeaders();
 		} else if(e instanceof SubscriptionRemovedEvent) {
-			if(((SubscriptionRemovedEvent) e).getGroupId().equals(groupId)) {
+			SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e;
+			if(s.getGroup().getId().equals(groupId)) {
 				if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
 				finishOnUiThread();
 			}
@@ -214,6 +218,7 @@ OnClickListener, OnItemClickListener {
 
 	public void onClick(View view) {
 		Intent i = new Intent(this, WriteGroupMessageActivity.class);
+		i.putExtra("net.sf.briar.RESTRICTED", restricted);
 		i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
 		startActivity(i);
 	}
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
index f1885f6102..70d797bb35 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -1,6 +1,8 @@
 package net.sf.briar.android.groups;
 
+import static android.view.Gravity.CENTER;
 import static android.view.Gravity.CENTER_HORIZONTAL;
+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;
@@ -26,6 +28,7 @@ import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.CommonLayoutParams;
 import net.sf.briar.android.widgets.HorizontalBorder;
+import net.sf.briar.android.widgets.HorizontalSpace;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.crypto.CryptoComponent;
@@ -67,6 +70,7 @@ implements OnClickListener, DatabaseListener {
 
 	private GroupListAdapter adapter = null;
 	private ListView list = null;
+	private ImageButton newGroupButton = null, composeButton = null;
 
 	// Fields that are accessed from DB threads must be volatile
 	@Inject private volatile CryptoComponent crypto;
@@ -76,6 +80,7 @@ implements OnClickListener, DatabaseListener {
 	@Inject private volatile AuthorFactory authorFactory;
 	@Inject private volatile GroupFactory groupFactory;
 	@Inject private volatile MessageFactory messageFactory;
+	private volatile boolean restricted = false;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -85,6 +90,12 @@ implements OnClickListener, DatabaseListener {
 		layout.setOrientation(VERTICAL);
 		layout.setGravity(CENTER_HORIZONTAL);
 
+		Intent i = getIntent();
+		restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
+		String title = i.getStringExtra("net.sf.briar.TITLE");
+		if(title == null) throw new IllegalStateException();
+		setTitle(title);
+
 		adapter = new GroupListAdapter(this);
 		list = new ListView(this);
 		// Give me all the width and all the unused height
@@ -95,11 +106,28 @@ implements OnClickListener, DatabaseListener {
 
 		layout.addView(new HorizontalBorder(this));
 
-		ImageButton newGroupButton = new ImageButton(this);
+		LinearLayout footer = new LinearLayout(this);
+		footer.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
+		footer.setOrientation(HORIZONTAL);
+		footer.setGravity(CENTER);
+		footer.addView(new HorizontalSpace(this));
+
+		newGroupButton = new ImageButton(this);
 		newGroupButton.setBackgroundResource(0);
-		newGroupButton.setImageResource(R.drawable.social_new_chat);
+		if(restricted)
+			newGroupButton.setImageResource(R.drawable.social_new_blog);
+		else newGroupButton.setImageResource(R.drawable.social_new_chat);
 		newGroupButton.setOnClickListener(this);
-		layout.addView(newGroupButton);
+		footer.addView(newGroupButton);
+		footer.addView(new HorizontalSpace(this));
+
+		composeButton = new ImageButton(this);
+		composeButton.setBackgroundResource(0);
+		composeButton.setImageResource(R.drawable.content_new_email);
+		composeButton.setOnClickListener(this);
+		footer.addView(composeButton);
+		footer.addView(new HorizontalSpace(this));
+		layout.addView(footer);
 
 		setContentView(layout);
 
@@ -146,7 +174,11 @@ implements OnClickListener, DatabaseListener {
 					Group group1 = groupFactory.createGroup("Godwin's Lore");
 					db.subscribe(group1);
 					db.setVisibility(group1.getId(), Arrays.asList(contactId));
-					// Insert some text messages to the groups
+					Group group2 = groupFactory.createGroup(
+							"All Kids Love Blog", publicKey);
+					db.subscribe(group2);
+					db.setVisibility(group2.getId(), Arrays.asList(contactId));
+					// Insert some text messages to the unrestricted groups
 					for(int i = 0; i < 20; i++) {
 						String body;
 						if(i % 3 == 0) {
@@ -197,6 +229,43 @@ implements OnClickListener, DatabaseListener {
 					m = messageFactory.createAnonymousMessage(m.getId(),
 							group1, "text/plain", body.getBytes("UTF-8"));
 					db.addLocalGroupMessage(m);
+					// Insert some text messages to the restricted group
+					for(int i = 0; i < 20; i++) {
+						if(i % 3 == 0) {
+							body = "Message " + i + " is short.";
+						} else { 
+							body = "Message " + i + " is long enough to wrap"
+									+ " onto a second line on some screens.";
+						}
+						now = System.currentTimeMillis();
+						if(i % 5 == 0) {
+							m = messageFactory.createAnonymousMessage(null,
+									group2, privateKey, "text/plain",
+									body.getBytes("UTF-8"));
+						} else if(i % 5 == 2) {
+							m = messageFactory.createPseudonymousMessage(null,
+									group2, privateKey, author, privateKey,
+									"text/plain", body.getBytes("UTF-8"));
+						} else {
+							m = messageFactory.createPseudonymousMessage(null,
+									group2, privateKey, author1, privateKey,
+									"text/plain", body.getBytes("UTF-8"));
+						}
+						duration = System.currentTimeMillis() - now;
+						if(LOG.isLoggable(INFO)) {
+							LOG.info("Message creation took " +
+									duration + " ms");
+						}
+						now = System.currentTimeMillis();
+						if(Math.random() < 0.5) db.addLocalGroupMessage(m);
+						else db.receiveMessage(contactId, m);
+						db.setReadFlag(m.getId(), i % 4 == 0);
+						duration = System.currentTimeMillis() - now;
+						if(LOG.isLoggable(INFO)) {
+							LOG.info("Message storage took " +
+									duration + " ms");
+						}
+					}
 				} catch(DbException e) {
 					if(LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -233,8 +302,8 @@ implements OnClickListener, DatabaseListener {
 							new ArrayList<CountDownLatch>();
 					long now = System.currentTimeMillis();
 					for(Group g : db.getSubscriptions()) {
-						// Filter out restricted groups
-						if(g.getPublicKey() != null) continue;
+						// Filter out restricted/unrestricted groups
+						if(g.isRestricted() != restricted) continue;
 						try {
 							// Load the headers from the database
 							Collection<GroupMessageHeader> headers =
@@ -322,41 +391,52 @@ implements OnClickListener, DatabaseListener {
 	}
 
 	public void onClick(View view) {
-		startActivity(new Intent(this, WriteGroupMessageActivity.class));
+		if(view == newGroupButton) {
+			// FIXME: Hook this button up to an activity
+		} else if(view == composeButton) {
+			Intent i = new Intent(this, WriteGroupMessageActivity.class);
+			i.putExtra("net.sf.briar.RESTRICTED", restricted);
+			startActivity(i);
+		}
 	}
 
 	public void eventOccurred(DatabaseEvent e) {
 		if(e instanceof GroupMessageAddedEvent) {
-			if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
-			loadHeaders(((GroupMessageAddedEvent) e).getGroupId());
+			Group g = ((GroupMessageAddedEvent) e).getGroup();
+			if(g.isRestricted() == restricted) {
+				if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
+				loadHeaders(g);
+			}
 		} else if(e instanceof MessageExpiredEvent) {
 			if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
 			loadHeaders(); // FIXME: Don't reload everything
 		} else if(e instanceof SubscriptionRemovedEvent) {
 			// Reload the group, expecting NoSuchSubscriptionException
-			if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
-			loadHeaders(((SubscriptionRemovedEvent) e).getGroupId());
+			Group g = ((SubscriptionRemovedEvent) e).getGroup();
+			if(g.isRestricted() == restricted) {
+				if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
+				loadHeaders(g);
+			}
 		}
 	}
 
-	private void loadHeaders(final GroupId g) {
+	private void loadHeaders(final Group g) {
 		dbUiExecutor.execute(new Runnable() {
 			public void run() {
 				try {
 					serviceConnection.waitForStartup();
 					long now = System.currentTimeMillis();
-					Group group = db.getGroup(g);
 					Collection<GroupMessageHeader> headers =
-							db.getMessageHeaders(g);
+							db.getMessageHeaders(g.getId());
 					long duration = System.currentTimeMillis() - now;
 					if(LOG.isLoggable(INFO))
 						LOG.info("Partial load took " + duration + " ms");
 					CountDownLatch latch = new CountDownLatch(1);
-					displayHeaders(latch, group, headers);
+					displayHeaders(latch, g, headers);
 					latch.await();
 				} catch(NoSuchSubscriptionException e) {
 					if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
-					removeGroup(g);
+					removeGroup(g.getId());
 				} catch(DbException e) {
 					if(LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
diff --git a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
index 6dd8792ea6..38b8ce59da 100644
--- a/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/WriteGroupMessageActivity.java
@@ -53,6 +53,7 @@ implements OnClickListener, OnItemSelectedListener {
 			new BriarServiceConnection();
 
 	@Inject private BundleEncrypter bundleEncrypter;
+	private boolean restricted = false;
 	private GroupNameSpinnerAdapter adapter = null;
 	private Spinner spinner = null;
 	private ImageButton sendButton = null;
@@ -71,6 +72,7 @@ implements OnClickListener, OnItemSelectedListener {
 		super.onCreate(null);
 
 		Intent i = getIntent();
+		restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
 		byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
 		if(id != null) groupId = new GroupId(id);
 		id = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
@@ -123,6 +125,7 @@ implements OnClickListener, OnItemSelectedListener {
 				serviceConnection, 0);
 	}
 
+	// FIXME: If restricted, only load groups the user can post to
 	private void loadGroupList() {
 		dbExecutor.execute(new Runnable() {
 			public void run() {
@@ -144,6 +147,7 @@ implements OnClickListener, OnItemSelectedListener {
 		runOnUiThread(new Runnable() {
 			public void run() {
 				for(Group g : groups) {
+					if(g.isRestricted() != restricted) continue;
 					if(g.getId().equals(groupId)) {
 						group = g;
 						spinner.setSelection(adapter.getCount());
diff --git a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
index 3e466d1918..add29d7abd 100644
--- a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
+++ b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java
@@ -327,5 +327,5 @@ public interface DatabaseComponent {
 	 * Unsubscribes from the given group. Any messages belonging to the group
 	 * are deleted from the database.
 	 */
-	void unsubscribe(GroupId g) throws DbException;
+	void unsubscribe(Group g) throws DbException;
 }
diff --git a/briar-api/src/net/sf/briar/api/db/event/GroupMessageAddedEvent.java b/briar-api/src/net/sf/briar/api/db/event/GroupMessageAddedEvent.java
index 0a66d81f4a..40c5510301 100644
--- a/briar-api/src/net/sf/briar/api/db/event/GroupMessageAddedEvent.java
+++ b/briar-api/src/net/sf/briar/api/db/event/GroupMessageAddedEvent.java
@@ -1,20 +1,20 @@
 package net.sf.briar.api.db.event;
 
-import net.sf.briar.api.messaging.GroupId;
+import net.sf.briar.api.messaging.Group;
 
 /** An event that is broadcast when a group message is added to the database. */
 public class GroupMessageAddedEvent extends DatabaseEvent {
 
-	private final GroupId groupId;
+	private final Group group;
 	private final boolean incoming;
 
-	public GroupMessageAddedEvent(GroupId groupId, boolean incoming) {
-		this.groupId = groupId;
+	public GroupMessageAddedEvent(Group group, boolean incoming) {
+		this.group = group;
 		this.incoming = incoming;
 	}
 
-	public GroupId getGroupId() {
-		return groupId;
+	public Group getGroup() {
+		return group;
 	}
 
 	public boolean isIncoming() {
diff --git a/briar-api/src/net/sf/briar/api/db/event/SubscriptionRemovedEvent.java b/briar-api/src/net/sf/briar/api/db/event/SubscriptionRemovedEvent.java
index df7f5bf934..2957304efc 100644
--- a/briar-api/src/net/sf/briar/api/db/event/SubscriptionRemovedEvent.java
+++ b/briar-api/src/net/sf/briar/api/db/event/SubscriptionRemovedEvent.java
@@ -1,17 +1,17 @@
 package net.sf.briar.api.db.event;
 
-import net.sf.briar.api.messaging.GroupId;
+import net.sf.briar.api.messaging.Group;
 
 /** An event that is broadcast when the user unsubscribes from a group. */
 public class SubscriptionRemovedEvent extends DatabaseEvent {
 
-	private final GroupId groupId;
+	private final Group group;
 
-	public SubscriptionRemovedEvent(GroupId groupId) {
-		this.groupId = groupId;
+	public SubscriptionRemovedEvent(Group group) {
+		this.group = group;
 	}
 
-	public GroupId getGroupId() {
-		return groupId;
+	public Group getGroup() {
+		return group;
 	}
 }
diff --git a/briar-api/src/net/sf/briar/api/messaging/Group.java b/briar-api/src/net/sf/briar/api/messaging/Group.java
index 3e1bf6466f..71d260ac84 100644
--- a/briar-api/src/net/sf/briar/api/messaging/Group.java
+++ b/briar-api/src/net/sf/briar/api/messaging/Group.java
@@ -23,6 +23,11 @@ public class Group {
 		return name;
 	}
 
+	/** Returns true if the group is restricted. */
+	public boolean isRestricted() {
+		return publicKey != null;
+	}
+
 	/**
 	 * If the group is restricted, returns the public key that is used to
 	 * authorise all messages sent to the group. Otherwise returns null.
diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
index 99dc9c162a..f5184749ca 100644
--- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java
@@ -287,10 +287,8 @@ DatabaseCleaner.Callback {
 		} finally {
 			contactLock.readLock().unlock();
 		}
-		if(added) {
-			GroupId g = m.getGroup().getId();
-			callListeners(new GroupMessageAddedEvent(g, false));
-		}
+		if(added)
+			callListeners(new GroupMessageAddedEvent(m.getGroup(), false));
 	}
 
 	/**
@@ -1357,7 +1355,7 @@ DatabaseCleaner.Callback {
 		if(added) {
 			Group g = m.getGroup();
 			if(g == null) callListeners(new PrivateMessageAddedEvent(c, true));
-			else callListeners(new GroupMessageAddedEvent(g.getId(), true));
+			else callListeners(new GroupMessageAddedEvent(g, true));
 		}
 	}
 
@@ -1855,7 +1853,7 @@ DatabaseCleaner.Callback {
 		return added;
 	}
 
-	public void unsubscribe(GroupId g) throws DbException {
+	public void unsubscribe(Group g) throws DbException {
 		Collection<ContactId> affected;
 		messageLock.writeLock().lock();
 		try {
@@ -1863,10 +1861,11 @@ DatabaseCleaner.Callback {
 			try {
 				T txn = db.startTransaction();
 				try {
-					if(!db.containsSubscription(txn, g))
+					GroupId id = g.getId();
+					if(!db.containsSubscription(txn, id))
 						throw new NoSuchSubscriptionException();
-					affected = db.getVisibility(txn, g);
-					db.removeSubscription(txn, g);
+					affected = db.getVisibility(txn, id);
+					db.removeSubscription(txn, id);
 					db.commitTransaction(txn);
 				} catch(DbException e) {
 					db.abortTransaction(txn);
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index 854fe74e73..c9834381a5 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -823,7 +823,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, g.getId().getBytes());
 			ps.setString(2, g.getName());
-			ps.setBytes(3, g.getPublicKey());
+			if(g.isRestricted()) ps.setBytes(3, g.getPublicKey());
+			else ps.setNull(3, BINARY);
 			int affected = ps.executeUpdate();
 			if(affected != 1) throw new DbStateException();
 			ps.close();
@@ -3029,9 +3030,8 @@ abstract class JdbcDatabase implements Database<Connection> {
 			for(Group g : subs) {
 				ps.setBytes(2, g.getId().getBytes());
 				ps.setString(3, g.getName());
-				byte[] key = g.getPublicKey();
-				if(key == null) ps.setNull(4, BINARY);
-				else ps.setBytes(4, key);
+				if(g.isRestricted()) ps.setBytes(4, g.getPublicKey());
+				else ps.setNull(4, BINARY);
 				ps.addBatch();
 			}
 			int[] affectedBatch = ps.executeBatch();
diff --git a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
index a66b3b6bf2..a6c93b06ed 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java
@@ -99,8 +99,7 @@ class MessageFactoryImpl implements MessageFactory {
 		// Validate the arguments
 		if((author == null) != (authorKey == null))
 			throw new IllegalArgumentException();
-		if((group == null || group.getPublicKey() == null)
-				!= (groupKey == null))
+		if((group == null || !group.isRestricted()) != (groupKey == null))
 			throw new IllegalArgumentException();
 		if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH)
 			throw new IllegalArgumentException();
@@ -182,9 +181,8 @@ class MessageFactoryImpl implements MessageFactory {
 	private void writeGroup(Writer w, Group g) throws IOException {
 		w.writeStructId(GROUP);
 		w.writeString(g.getName());
-		byte[] publicKey = g.getPublicKey();
-		if(publicKey == null) w.writeNull();
-		else w.writeBytes(publicKey);
+		if(g.isRestricted()) w.writeBytes(g.getPublicKey());
+		else w.writeNull();
 	}
 
 	private void writeAuthor(Writer w, Author a) throws IOException {
diff --git a/briar-core/src/net/sf/briar/messaging/MessageReader.java b/briar-core/src/net/sf/briar/messaging/MessageReader.java
index de0bf74ac5..73c0550516 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageReader.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageReader.java
@@ -93,7 +93,7 @@ class MessageReader implements StructReader<UnverifiedMessage> {
 		int signedByGroup = (int) counting.getCount();
 		// Read the group's signature, if there is one
 		byte[] groupSig = null;
-		if(group == null || group.getPublicKey() == null) r.readNull();
+		if(group == null || !group.isRestricted()) r.readNull();
 		else groupSig = r.readBytes(MAX_SIGNATURE_LENGTH);
 		// That's all, folks
 		r.removeConsumer(counting);
diff --git a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
index 22abc26555..de57bbb3a1 100644
--- a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java
@@ -46,7 +46,7 @@ class MessageVerifierImpl implements MessageVerifier {
 		}
 		// Verify the group's signature, if there is one
 		Group group = m.getGroup();
-		if(group != null && group.getPublicKey() != null) {
+		if(group != null && group.isRestricted()) {
 			PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
 			signature.initVerify(k);
 			signature.update(raw, 0, m.getLengthSignedByGroup());
diff --git a/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java b/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java
index 0e54cec9b9..067881cb56 100644
--- a/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java
+++ b/briar-core/src/net/sf/briar/messaging/PacketWriterImpl.java
@@ -133,9 +133,8 @@ class PacketWriterImpl implements PacketWriter {
 		for(Group g : u.getGroups()) {
 			w.writeStructId(GROUP);
 			w.writeString(g.getName());
-			byte[] publicKey = g.getPublicKey();
-			if(publicKey == null) w.writeNull();
-			else w.writeBytes(publicKey);
+			if(g.isRestricted()) w.writeBytes(g.getPublicKey());
+			else w.writeNull();
 		}
 		w.writeListEnd();
 		w.writeInt64(u.getVersion());
diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
index e59726b0f8..61bc729a9d 100644
--- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
+++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java
@@ -204,8 +204,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 		db.subscribe(group); // Second time - not called
 		assertEquals(Collections.emptyList(), db.getMessageHeaders(groupId));
 		assertEquals(Arrays.asList(groupId), db.getSubscriptions());
-		db.unsubscribe(groupId); // Listeners called
-		db.removeContact(contactId); // Listeners called
+		db.unsubscribe(group);
+		db.removeContact(contactId);
 		db.removeListener(listener);
 		db.close();
 
@@ -707,7 +707,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
 		} catch(NoSuchSubscriptionException expected) {}
 
 		try {
-			db.unsubscribe(groupId);
+			db.unsubscribe(group);
 			fail();
 		} catch(NoSuchSubscriptionException expected) {}
 
-- 
GitLab