From 4e5366509d9f913f22b58f1b61e8fd843d458797 Mon Sep 17 00:00:00 2001 From: akwizgran 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 fc8fcd528..ad48f4aea 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -42,15 +42,15 @@ + android:label="@string/app_name" > + android:label="@string/app_name" > + android:label="@string/app_name" > 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?@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}TFXTitlfnXwAmritN=pbj+#;xIInlh2BN0kkc`}MlknKo9!1mKrn3O(18zHwC)7W#>U5Wk zVcn|lyM;%rl6%%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!`oEn30000Px#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@_)gr7XxNo(X=d6DQq;kCGtS9E` z0hfWraRbl-{`aiAfJVS>;E;YV09OTSv|RvdIqRntfggbzwQ 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(fTT5|UatWk zipYTjW*zvd>Ii(Us*_cjy7RjYybhcau=|F*nf;>*)-lzoq3?F91aL|_9&8|9hZLa*VU{oDd%6(^O-}5Do?``iFK**F{j50^`34O z0RE8Zq&ecX2;7!%HJwN#zyT+6uJxqYEhlQP06$d$ph!Esrhe&&^55l0TWL2md}#|H zP89ByQRt#dd_Xz7Do5PZxD6b2Kx62Y5qkO9n(&+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~S6J1PzhCVK~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-ApqGVVBlzjcrqmH0L(>e%kIQFTJA%Fz;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)Px$=t)FDR9M69*3D{DVGsu3CykOg5HF< zQ$eICSP)4I5vgzd#jjEaKTP1gbq^*V3A?AX}8kAB}ZCqB=WTf%Eu)R@gPvF@>2_ zjm{Zg@wh~CC<6U(2G_AWk@)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 zcmVPx#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*d7C7=R~1Cu5i$-3{rE01JP1opx?;3hC&$m{?wJESgi3iiS}@D3OT#>^fU zq>Y{lRDddQ2{@~Y*j2tQ>cBQ|+6eRv@S#@%4}s&rF^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&`E$@)8JBgcwVN`vRZ98>u@shi?J1X3m7hV_?IKm(054HpMwN z;+!jI5#bA9S*>?jw#B4E9eRv?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@jmlEFyFz*X?WHBrz|KL5Fc6X8pa={W i*$47qDa#Y>pW`pm9GgjZFSo7$0000Px&P)S5VRCwC$nM+R-Q5?m8l=sUNA;m|rkf5oLg^3$uT)E*35Ka65el7QgFTlbT zi7TTqnphVi1OY*yC17m;TNnH%X~^7rdxzoeX=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$*L7iEyjQ;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>H34yzN>6o4|Xi)0!dsx03Ws{e2s_uejGiIo2rw2W?1tcSX(( zMQrX@s3{A4K2I)i6@^Vn&(zbF{4apK=C~D59>iOfY37EGW8|F1D8fB@b z>AQ;U6Rru!SdPsrY8p*VtDpN>cN>Irp^}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)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@gx84fUVmUEv1Z8vQY>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>li)E)=w(uN2;;CY;_Yh4~4~i|GgcPMZ@fcsRXRj&zs;{)*c+ z$7O}56cJAxxxC^K#v<@AP6F~Vul++48gfg~&iXco~ypE0$&)O z>5#tLQ3A>_IK8t9=g452hYZnF03O8Q3)*dkT~5zc-?tP6ri$@8=>*gswAK2)E!A%{ zTp5TX4f;Hiwai&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 + #FFFFFF #FFFFFF #FFFFFF #CCCCCC diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 14258e047..5881c29be 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -44,7 +44,8 @@ To: %1$s New Message To: - Groups (Anonymous) + Groups New Post + Blogs diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java index 02cea07ef..3cf515905 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 deff171b8..43af87cf9 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 f1885f610..70d797bb3 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(); 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 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 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 6dd8792ea..38b8ce59d 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 3e466d191..add29d7ab 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 0a66d81f4..40c551030 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 df7f5bf93..2957304ef 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 3e1bf6466..71d260ac8 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 99dc9c162..f5184749c 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 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 854fe74e7..c9834381a 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 { 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 { 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 a66b3b6bf..a6c93b06e 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 de0bf74ac..73c055051 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 { 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 22abc2655..de57bbb3a 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 0e54cec9b..067881cb5 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 e59726b0f..61bc729a9 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) {}