mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Android UI for blogs (restricted groups).
This commit is contained in:
@@ -42,15 +42,15 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.groups.GroupActivity"
|
android:name=".android.groups.GroupActivity"
|
||||||
android:label="@string/groups_title" >
|
android:label="@string/app_name" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.groups.GroupListActivity"
|
android:name=".android.groups.GroupListActivity"
|
||||||
android:label="@string/groups_title" >
|
android:label="@string/app_name" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.groups.ReadGroupMessageActivity"
|
android:name=".android.groups.ReadGroupMessageActivity"
|
||||||
android:label="@string/groups_title" >
|
android:label="@string/app_name" >
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.groups.WriteGroupMessageActivity"
|
android:name=".android.groups.WriteGroupMessageActivity"
|
||||||
|
|||||||
BIN
briar-android/res/drawable-hdpi/social_blog.png
Normal file
BIN
briar-android/res/drawable-hdpi/social_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 948 B |
BIN
briar-android/res/drawable-hdpi/social_new_blog.png
Normal file
BIN
briar-android/res/drawable-hdpi/social_new_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
briar-android/res/drawable-mdpi/social_blog.png
Normal file
BIN
briar-android/res/drawable-mdpi/social_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 558 B |
BIN
briar-android/res/drawable-mdpi/social_new_blog.png
Normal file
BIN
briar-android/res/drawable-mdpi/social_new_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 752 B |
BIN
briar-android/res/drawable-xhdpi/social_blog.png
Normal file
BIN
briar-android/res/drawable-xhdpi/social_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 918 B |
BIN
briar-android/res/drawable-xhdpi/social_new_blog.png
Normal file
BIN
briar-android/res/drawable-xhdpi/social_new_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<color name="home_screen_background">#FFFFFF</color>
|
||||||
<color name="content_background">#FFFFFF</color>
|
<color name="content_background">#FFFFFF</color>
|
||||||
<color name="unread_background">#FFFFFF</color>
|
<color name="unread_background">#FFFFFF</color>
|
||||||
<color name="horizontal_border">#CCCCCC</color>
|
<color name="horizontal_border">#CCCCCC</color>
|
||||||
|
|||||||
@@ -44,7 +44,8 @@
|
|||||||
<string name="format_to">To: %1$s</string>
|
<string name="format_to">To: %1$s</string>
|
||||||
<string name="compose_message_title">New Message</string>
|
<string name="compose_message_title">New Message</string>
|
||||||
<string name="to">To:</string>
|
<string name="to">To:</string>
|
||||||
<string name="groups_title">Groups</string>
|
|
||||||
<string name="anonymous">(Anonymous)</string>
|
<string name="anonymous">(Anonymous)</string>
|
||||||
|
<string name="groups_title">Groups</string>
|
||||||
<string name="compose_group_title">New Post</string>
|
<string name="compose_group_title">New Post</string>
|
||||||
|
<string name="blogs_title">Blogs</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -89,8 +89,12 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
groupsButton.setText(R.string.groups_button);
|
groupsButton.setText(R.string.groups_button);
|
||||||
groupsButton.setOnClickListener(new OnClickListener() {
|
groupsButton.setOnClickListener(new OnClickListener() {
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
startActivity(new Intent(HomeScreenActivity.this,
|
Intent i = new Intent(HomeScreenActivity.this,
|
||||||
GroupListActivity.class));
|
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);
|
buttons.add(groupsButton);
|
||||||
@@ -99,11 +103,16 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
blogsButton.setLayoutParams(matchParent);
|
blogsButton.setLayoutParams(matchParent);
|
||||||
blogsButton.setBackgroundResource(0);
|
blogsButton.setBackgroundResource(0);
|
||||||
blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
|
blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
|
||||||
R.drawable.social_share, 0, 0);
|
R.drawable.social_blog, 0, 0);
|
||||||
blogsButton.setText(R.string.blogs_button);
|
blogsButton.setText(R.string.blogs_button);
|
||||||
blogsButton.setOnClickListener(new OnClickListener() {
|
blogsButton.setOnClickListener(new OnClickListener() {
|
||||||
public void onClick(View view) {
|
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);
|
buttons.add(blogsButton);
|
||||||
@@ -138,6 +147,8 @@ public class HomeScreenActivity extends BriarActivity {
|
|||||||
grid.setLayoutParams(matchParent);
|
grid.setLayoutParams(matchParent);
|
||||||
grid.setGravity(CENTER);
|
grid.setGravity(CENTER);
|
||||||
grid.setPadding(5, 5, 5, 5);
|
grid.setPadding(5, 5, 5, 5);
|
||||||
|
grid.setBackgroundColor(getResources().getColor(
|
||||||
|
R.color.home_screen_background));
|
||||||
grid.setNumColumns(2);
|
grid.setNumColumns(2);
|
||||||
grid.setAdapter(new BaseAdapter() {
|
grid.setAdapter(new BaseAdapter() {
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ OnClickListener, OnItemClickListener {
|
|||||||
private final BriarServiceConnection serviceConnection =
|
private final BriarServiceConnection serviceConnection =
|
||||||
new BriarServiceConnection();
|
new BriarServiceConnection();
|
||||||
|
|
||||||
|
private boolean restricted = false;
|
||||||
private String groupName = null;
|
private String groupName = null;
|
||||||
private GroupAdapter adapter = null;
|
private GroupAdapter adapter = null;
|
||||||
private ListView list = null;
|
private ListView list = null;
|
||||||
@@ -65,6 +66,7 @@ OnClickListener, OnItemClickListener {
|
|||||||
super.onCreate(null);
|
super.onCreate(null);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
|
restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
|
||||||
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
|
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
|
||||||
if(id == null) throw new IllegalStateException();
|
if(id == null) throw new IllegalStateException();
|
||||||
groupId = new GroupId(id);
|
groupId = new GroupId(id);
|
||||||
@@ -194,7 +196,8 @@ OnClickListener, OnItemClickListener {
|
|||||||
|
|
||||||
public void eventOccurred(DatabaseEvent e) {
|
public void eventOccurred(DatabaseEvent e) {
|
||||||
if(e instanceof GroupMessageAddedEvent) {
|
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");
|
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
}
|
}
|
||||||
@@ -205,7 +208,8 @@ OnClickListener, OnItemClickListener {
|
|||||||
if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
|
if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
|
||||||
loadHeaders();
|
loadHeaders();
|
||||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
} 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");
|
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
}
|
}
|
||||||
@@ -214,6 +218,7 @@ OnClickListener, OnItemClickListener {
|
|||||||
|
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Intent i = new Intent(this, WriteGroupMessageActivity.class);
|
Intent i = new Intent(this, WriteGroupMessageActivity.class);
|
||||||
|
i.putExtra("net.sf.briar.RESTRICTED", restricted);
|
||||||
i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
|
i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package net.sf.briar.android.groups;
|
package net.sf.briar.android.groups;
|
||||||
|
|
||||||
|
import static android.view.Gravity.CENTER;
|
||||||
import static android.view.Gravity.CENTER_HORIZONTAL;
|
import static android.view.Gravity.CENTER_HORIZONTAL;
|
||||||
|
import static android.widget.LinearLayout.HORIZONTAL;
|
||||||
import static android.widget.LinearLayout.VERTICAL;
|
import static android.widget.LinearLayout.VERTICAL;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
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.BriarService.BriarServiceConnection;
|
||||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||||
import net.sf.briar.android.widgets.HorizontalBorder;
|
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.ContactId;
|
||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
@@ -67,6 +70,7 @@ implements OnClickListener, DatabaseListener {
|
|||||||
|
|
||||||
private GroupListAdapter adapter = null;
|
private GroupListAdapter adapter = null;
|
||||||
private ListView list = null;
|
private ListView list = null;
|
||||||
|
private ImageButton newGroupButton = null, composeButton = null;
|
||||||
|
|
||||||
// Fields that are accessed from DB threads must be volatile
|
// Fields that are accessed from DB threads must be volatile
|
||||||
@Inject private volatile CryptoComponent crypto;
|
@Inject private volatile CryptoComponent crypto;
|
||||||
@@ -76,6 +80,7 @@ implements OnClickListener, DatabaseListener {
|
|||||||
@Inject private volatile AuthorFactory authorFactory;
|
@Inject private volatile AuthorFactory authorFactory;
|
||||||
@Inject private volatile GroupFactory groupFactory;
|
@Inject private volatile GroupFactory groupFactory;
|
||||||
@Inject private volatile MessageFactory messageFactory;
|
@Inject private volatile MessageFactory messageFactory;
|
||||||
|
private volatile boolean restricted = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -85,6 +90,12 @@ implements OnClickListener, DatabaseListener {
|
|||||||
layout.setOrientation(VERTICAL);
|
layout.setOrientation(VERTICAL);
|
||||||
layout.setGravity(CENTER_HORIZONTAL);
|
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);
|
adapter = new GroupListAdapter(this);
|
||||||
list = new ListView(this);
|
list = new ListView(this);
|
||||||
// Give me all the width and all the unused height
|
// Give me all the width and all the unused height
|
||||||
@@ -95,11 +106,28 @@ implements OnClickListener, DatabaseListener {
|
|||||||
|
|
||||||
layout.addView(new HorizontalBorder(this));
|
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.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);
|
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);
|
setContentView(layout);
|
||||||
|
|
||||||
@@ -146,7 +174,11 @@ implements OnClickListener, DatabaseListener {
|
|||||||
Group group1 = groupFactory.createGroup("Godwin's Lore");
|
Group group1 = groupFactory.createGroup("Godwin's Lore");
|
||||||
db.subscribe(group1);
|
db.subscribe(group1);
|
||||||
db.setVisibility(group1.getId(), Arrays.asList(contactId));
|
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++) {
|
for(int i = 0; i < 20; i++) {
|
||||||
String body;
|
String body;
|
||||||
if(i % 3 == 0) {
|
if(i % 3 == 0) {
|
||||||
@@ -197,6 +229,43 @@ implements OnClickListener, DatabaseListener {
|
|||||||
m = messageFactory.createAnonymousMessage(m.getId(),
|
m = messageFactory.createAnonymousMessage(m.getId(),
|
||||||
group1, "text/plain", body.getBytes("UTF-8"));
|
group1, "text/plain", body.getBytes("UTF-8"));
|
||||||
db.addLocalGroupMessage(m);
|
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) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if(LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -233,8 +302,8 @@ implements OnClickListener, DatabaseListener {
|
|||||||
new ArrayList<CountDownLatch>();
|
new ArrayList<CountDownLatch>();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for(Group g : db.getSubscriptions()) {
|
for(Group g : db.getSubscriptions()) {
|
||||||
// Filter out restricted groups
|
// Filter out restricted/unrestricted groups
|
||||||
if(g.getPublicKey() != null) continue;
|
if(g.isRestricted() != restricted) continue;
|
||||||
try {
|
try {
|
||||||
// Load the headers from the database
|
// Load the headers from the database
|
||||||
Collection<GroupMessageHeader> headers =
|
Collection<GroupMessageHeader> headers =
|
||||||
@@ -322,41 +391,52 @@ implements OnClickListener, DatabaseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClick(View view) {
|
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) {
|
public void eventOccurred(DatabaseEvent e) {
|
||||||
if(e instanceof GroupMessageAddedEvent) {
|
if(e instanceof GroupMessageAddedEvent) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
|
Group g = ((GroupMessageAddedEvent) e).getGroup();
|
||||||
loadHeaders(((GroupMessageAddedEvent) e).getGroupId());
|
if(g.isRestricted() == restricted) {
|
||||||
|
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
|
||||||
|
loadHeaders(g);
|
||||||
|
}
|
||||||
} else if(e instanceof MessageExpiredEvent) {
|
} else if(e instanceof MessageExpiredEvent) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
||||||
loadHeaders(); // FIXME: Don't reload everything
|
loadHeaders(); // FIXME: Don't reload everything
|
||||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
} else if(e instanceof SubscriptionRemovedEvent) {
|
||||||
// Reload the group, expecting NoSuchSubscriptionException
|
// Reload the group, expecting NoSuchSubscriptionException
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
|
Group g = ((SubscriptionRemovedEvent) e).getGroup();
|
||||||
loadHeaders(((SubscriptionRemovedEvent) e).getGroupId());
|
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() {
|
dbUiExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
serviceConnection.waitForStartup();
|
serviceConnection.waitForStartup();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Group group = db.getGroup(g);
|
|
||||||
Collection<GroupMessageHeader> headers =
|
Collection<GroupMessageHeader> headers =
|
||||||
db.getMessageHeaders(g);
|
db.getMessageHeaders(g.getId());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if(LOG.isLoggable(INFO))
|
if(LOG.isLoggable(INFO))
|
||||||
LOG.info("Partial load took " + duration + " ms");
|
LOG.info("Partial load took " + duration + " ms");
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
displayHeaders(latch, group, headers);
|
displayHeaders(latch, g, headers);
|
||||||
latch.await();
|
latch.await();
|
||||||
} catch(NoSuchSubscriptionException e) {
|
} catch(NoSuchSubscriptionException e) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
||||||
removeGroup(g);
|
removeGroup(g.getId());
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if(LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
new BriarServiceConnection();
|
new BriarServiceConnection();
|
||||||
|
|
||||||
@Inject private BundleEncrypter bundleEncrypter;
|
@Inject private BundleEncrypter bundleEncrypter;
|
||||||
|
private boolean restricted = false;
|
||||||
private GroupNameSpinnerAdapter adapter = null;
|
private GroupNameSpinnerAdapter adapter = null;
|
||||||
private Spinner spinner = null;
|
private Spinner spinner = null;
|
||||||
private ImageButton sendButton = null;
|
private ImageButton sendButton = null;
|
||||||
@@ -71,6 +72,7 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
super.onCreate(null);
|
super.onCreate(null);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
|
restricted = i.getBooleanExtra("net.sf.briar.RESTRICTED", false);
|
||||||
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
|
byte[] id = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
|
||||||
if(id != null) groupId = new GroupId(id);
|
if(id != null) groupId = new GroupId(id);
|
||||||
id = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
|
id = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
|
||||||
@@ -123,6 +125,7 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
serviceConnection, 0);
|
serviceConnection, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: If restricted, only load groups the user can post to
|
||||||
private void loadGroupList() {
|
private void loadGroupList() {
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -144,6 +147,7 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
for(Group g : groups) {
|
for(Group g : groups) {
|
||||||
|
if(g.isRestricted() != restricted) continue;
|
||||||
if(g.getId().equals(groupId)) {
|
if(g.getId().equals(groupId)) {
|
||||||
group = g;
|
group = g;
|
||||||
spinner.setSelection(adapter.getCount());
|
spinner.setSelection(adapter.getCount());
|
||||||
|
|||||||
@@ -327,5 +327,5 @@ public interface DatabaseComponent {
|
|||||||
* Unsubscribes from the given group. Any messages belonging to the group
|
* Unsubscribes from the given group. Any messages belonging to the group
|
||||||
* are deleted from the database.
|
* are deleted from the database.
|
||||||
*/
|
*/
|
||||||
void unsubscribe(GroupId g) throws DbException;
|
void unsubscribe(Group g) throws DbException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package net.sf.briar.api.db.event;
|
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. */
|
/** An event that is broadcast when a group message is added to the database. */
|
||||||
public class GroupMessageAddedEvent extends DatabaseEvent {
|
public class GroupMessageAddedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final GroupId groupId;
|
private final Group group;
|
||||||
private final boolean incoming;
|
private final boolean incoming;
|
||||||
|
|
||||||
public GroupMessageAddedEvent(GroupId groupId, boolean incoming) {
|
public GroupMessageAddedEvent(Group group, boolean incoming) {
|
||||||
this.groupId = groupId;
|
this.group = group;
|
||||||
this.incoming = incoming;
|
this.incoming = incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupId getGroupId() {
|
public Group getGroup() {
|
||||||
return groupId;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIncoming() {
|
public boolean isIncoming() {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package net.sf.briar.api.db.event;
|
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. */
|
/** An event that is broadcast when the user unsubscribes from a group. */
|
||||||
public class SubscriptionRemovedEvent extends DatabaseEvent {
|
public class SubscriptionRemovedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final GroupId groupId;
|
private final Group group;
|
||||||
|
|
||||||
public SubscriptionRemovedEvent(GroupId groupId) {
|
public SubscriptionRemovedEvent(Group group) {
|
||||||
this.groupId = groupId;
|
this.group = group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupId getGroupId() {
|
public Group getGroup() {
|
||||||
return groupId;
|
return group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ public class Group {
|
|||||||
return name;
|
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
|
* If the group is restricted, returns the public key that is used to
|
||||||
* authorise all messages sent to the group. Otherwise returns null.
|
* authorise all messages sent to the group. Otherwise returns null.
|
||||||
|
|||||||
@@ -287,10 +287,8 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
if(added) {
|
if(added)
|
||||||
GroupId g = m.getGroup().getId();
|
callListeners(new GroupMessageAddedEvent(m.getGroup(), false));
|
||||||
callListeners(new GroupMessageAddedEvent(g, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1357,7 +1355,7 @@ DatabaseCleaner.Callback {
|
|||||||
if(added) {
|
if(added) {
|
||||||
Group g = m.getGroup();
|
Group g = m.getGroup();
|
||||||
if(g == null) callListeners(new PrivateMessageAddedEvent(c, true));
|
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;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unsubscribe(GroupId g) throws DbException {
|
public void unsubscribe(Group g) throws DbException {
|
||||||
Collection<ContactId> affected;
|
Collection<ContactId> affected;
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1863,10 +1861,11 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
if(!db.containsSubscription(txn, g))
|
GroupId id = g.getId();
|
||||||
|
if(!db.containsSubscription(txn, id))
|
||||||
throw new NoSuchSubscriptionException();
|
throw new NoSuchSubscriptionException();
|
||||||
affected = db.getVisibility(txn, g);
|
affected = db.getVisibility(txn, id);
|
||||||
db.removeSubscription(txn, g);
|
db.removeSubscription(txn, id);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
|
|||||||
@@ -823,7 +823,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, g.getId().getBytes());
|
ps.setBytes(1, g.getId().getBytes());
|
||||||
ps.setString(2, g.getName());
|
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();
|
int affected = ps.executeUpdate();
|
||||||
if(affected != 1) throw new DbStateException();
|
if(affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -3029,9 +3030,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
for(Group g : subs) {
|
for(Group g : subs) {
|
||||||
ps.setBytes(2, g.getId().getBytes());
|
ps.setBytes(2, g.getId().getBytes());
|
||||||
ps.setString(3, g.getName());
|
ps.setString(3, g.getName());
|
||||||
byte[] key = g.getPublicKey();
|
if(g.isRestricted()) ps.setBytes(4, g.getPublicKey());
|
||||||
if(key == null) ps.setNull(4, BINARY);
|
else ps.setNull(4, BINARY);
|
||||||
else ps.setBytes(4, key);
|
|
||||||
ps.addBatch();
|
ps.addBatch();
|
||||||
}
|
}
|
||||||
int[] affectedBatch = ps.executeBatch();
|
int[] affectedBatch = ps.executeBatch();
|
||||||
|
|||||||
@@ -99,8 +99,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
// Validate the arguments
|
// Validate the arguments
|
||||||
if((author == null) != (authorKey == null))
|
if((author == null) != (authorKey == null))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if((group == null || group.getPublicKey() == null)
|
if((group == null || !group.isRestricted()) != (groupKey == null))
|
||||||
!= (groupKey == null))
|
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH)
|
if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -182,9 +181,8 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
private void writeGroup(Writer w, Group g) throws IOException {
|
private void writeGroup(Writer w, Group g) throws IOException {
|
||||||
w.writeStructId(GROUP);
|
w.writeStructId(GROUP);
|
||||||
w.writeString(g.getName());
|
w.writeString(g.getName());
|
||||||
byte[] publicKey = g.getPublicKey();
|
if(g.isRestricted()) w.writeBytes(g.getPublicKey());
|
||||||
if(publicKey == null) w.writeNull();
|
else w.writeNull();
|
||||||
else w.writeBytes(publicKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAuthor(Writer w, Author a) throws IOException {
|
private void writeAuthor(Writer w, Author a) throws IOException {
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
int signedByGroup = (int) counting.getCount();
|
int signedByGroup = (int) counting.getCount();
|
||||||
// Read the group's signature, if there is one
|
// Read the group's signature, if there is one
|
||||||
byte[] groupSig = null;
|
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);
|
else groupSig = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||||
// That's all, folks
|
// That's all, folks
|
||||||
r.removeConsumer(counting);
|
r.removeConsumer(counting);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class MessageVerifierImpl implements MessageVerifier {
|
|||||||
}
|
}
|
||||||
// Verify the group's signature, if there is one
|
// Verify the group's signature, if there is one
|
||||||
Group group = m.getGroup();
|
Group group = m.getGroup();
|
||||||
if(group != null && group.getPublicKey() != null) {
|
if(group != null && group.isRestricted()) {
|
||||||
PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
|
PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
|
||||||
signature.initVerify(k);
|
signature.initVerify(k);
|
||||||
signature.update(raw, 0, m.getLengthSignedByGroup());
|
signature.update(raw, 0, m.getLengthSignedByGroup());
|
||||||
|
|||||||
@@ -133,9 +133,8 @@ class PacketWriterImpl implements PacketWriter {
|
|||||||
for(Group g : u.getGroups()) {
|
for(Group g : u.getGroups()) {
|
||||||
w.writeStructId(GROUP);
|
w.writeStructId(GROUP);
|
||||||
w.writeString(g.getName());
|
w.writeString(g.getName());
|
||||||
byte[] publicKey = g.getPublicKey();
|
if(g.isRestricted()) w.writeBytes(g.getPublicKey());
|
||||||
if(publicKey == null) w.writeNull();
|
else w.writeNull();
|
||||||
else w.writeBytes(publicKey);
|
|
||||||
}
|
}
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeInt64(u.getVersion());
|
w.writeInt64(u.getVersion());
|
||||||
|
|||||||
@@ -204,8 +204,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
db.subscribe(group); // Second time - not called
|
db.subscribe(group); // Second time - not called
|
||||||
assertEquals(Collections.emptyList(), db.getMessageHeaders(groupId));
|
assertEquals(Collections.emptyList(), db.getMessageHeaders(groupId));
|
||||||
assertEquals(Arrays.asList(groupId), db.getSubscriptions());
|
assertEquals(Arrays.asList(groupId), db.getSubscriptions());
|
||||||
db.unsubscribe(groupId); // Listeners called
|
db.unsubscribe(group);
|
||||||
db.removeContact(contactId); // Listeners called
|
db.removeContact(contactId);
|
||||||
db.removeListener(listener);
|
db.removeListener(listener);
|
||||||
db.close();
|
db.close();
|
||||||
|
|
||||||
@@ -707,7 +707,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
} catch(NoSuchSubscriptionException expected) {}
|
} catch(NoSuchSubscriptionException expected) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.unsubscribe(groupId);
|
db.unsubscribe(group);
|
||||||
fail();
|
fail();
|
||||||
} catch(NoSuchSubscriptionException expected) {}
|
} catch(NoSuchSubscriptionException expected) {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user