mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Added spinners for selecting which identity to use.
(Although it isn't possible to create an identity yet...)
This commit is contained in:
@@ -13,15 +13,15 @@
|
||||
<string name="contact_connected">Connected</string>
|
||||
<string name="format_contact_last_connected">Last connected <br /> %1$s</string>
|
||||
<string name="add_contact_title">Add a Contact</string>
|
||||
<string name="choose_identity">Choose an identity to use with this contact:</string>
|
||||
<string name="wifi_not_available">Wi-Fi is not available on this device</string>
|
||||
<string name="your_identity">Your identity: </string>
|
||||
<string name="wifi_not_available">Wi-Fi is NOT AVAILABLE</string>
|
||||
<string name="wifi_disabled">Wi-Fi is OFF</string>
|
||||
<string name="wifi_disconnected">Wi-Fi is DISCONNECTED</string>
|
||||
<string name="format_wifi_connected">Wi-Fi is CONNECTED to %1$s</string>
|
||||
<string name="bluetooth_not_available">Bluetooth is not available on this device</string>
|
||||
<string name="format_wifi_connected">Wi-Fi is connected to %1$s</string>
|
||||
<string name="bluetooth_not_available">Bluetooth is NOT AVAILABLE</string>
|
||||
<string name="bluetooth_disabled">Bluetooth is OFF</string>
|
||||
<string name="bluetooth_not_discoverable">Bluetooth is NOT DISCOVERABLE</string>
|
||||
<string name="bluetooth_enabled">Bluetooth is DISCOVERABLE</string>
|
||||
<string name="bluetooth_enabled">Bluetooth is discoverable</string>
|
||||
<string name="continue_button">Continue</string>
|
||||
<string name="your_invitation_code">Your invitation code is</string>
|
||||
<string name="enter_invitation_code">Please enter your contact\'s invitation code:</string>
|
||||
@@ -43,7 +43,8 @@
|
||||
<string name="format_from">From: %1$s</string>
|
||||
<string name="format_to">To: %1$s</string>
|
||||
<string name="compose_message_title">New Message</string>
|
||||
<string name="to">To:</string>
|
||||
<string name="from">From: </string>
|
||||
<string name="to">To: </string>
|
||||
<string name="anonymous">(Anonymous)</string>
|
||||
<string name="groups_title">Groups</string>
|
||||
<string name="compose_group_title">New Post</string>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.sf.briar.android;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import net.sf.briar.api.Author;
|
||||
|
||||
public class AuthorNameComparator implements Comparator<Author> {
|
||||
|
||||
public static final AuthorNameComparator INSTANCE =
|
||||
new AuthorNameComparator();
|
||||
|
||||
public int compare(Author a1, Author a2) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(a1.getName(),
|
||||
a2.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.sf.briar.android;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.sf.briar.api.LocalAuthor;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.SpinnerAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class LocalAuthorNameSpinnerAdapter extends ArrayAdapter<LocalAuthor>
|
||||
implements SpinnerAdapter {
|
||||
|
||||
public LocalAuthorNameSpinnerAdapter(Context context) {
|
||||
super(context, android.R.layout.simple_spinner_item,
|
||||
new ArrayList<LocalAuthor>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView name = new TextView(getContext());
|
||||
name.setTextSize(18);
|
||||
name.setMaxLines(1);
|
||||
name.setPadding(10, 10, 10, 10);
|
||||
name.setText(getItem(position).getName());
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View convertView,
|
||||
ViewGroup parent) {
|
||||
return getView(position, convertView, parent);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -122,10 +121,8 @@ OnClickListener, OnItemClickListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
// Wait for the headers to be displayed in the UI
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, headers);
|
||||
latch.await();
|
||||
// Display the headers in the UI
|
||||
displayHeaders(headers);
|
||||
} catch(NoSuchSubscriptionException e) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
||||
finishOnUiThread();
|
||||
@@ -134,25 +131,20 @@ OnClickListener, OnItemClickListener {
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayHeaders(final CountDownLatch latch,
|
||||
final Collection<GroupMessageHeader> headers) {
|
||||
private void displayHeaders(final Collection<GroupMessageHeader> headers) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
adapter.clear();
|
||||
for(GroupMessageHeader h : headers) adapter.add(h);
|
||||
adapter.sort(AscendingHeaderComparator.INSTANCE);
|
||||
selectFirstUnread();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
adapter.clear();
|
||||
for(GroupMessageHeader h : headers) adapter.add(h);
|
||||
adapter.sort(AscendingHeaderComparator.INSTANCE);
|
||||
selectFirstUnread();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -203,7 +195,7 @@ OnClickListener, OnItemClickListener {
|
||||
}
|
||||
} else if(e instanceof MessageExpiredEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
||||
loadHeaders(); // FIXME: Don't reload everything
|
||||
loadHeaders();
|
||||
} else if(e instanceof RatingChangedEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
|
||||
loadHeaders();
|
||||
|
||||
@@ -11,7 +11,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -130,8 +129,6 @@ implements OnClickListener, DatabaseListener {
|
||||
// Wait for the service to be bound and started
|
||||
serviceConnection.waitForStartup();
|
||||
// Load the subscribed groups from the DB
|
||||
Collection<CountDownLatch> latches =
|
||||
new ArrayList<CountDownLatch>();
|
||||
long now = System.currentTimeMillis();
|
||||
for(Group g : db.getSubscriptions()) {
|
||||
// Filter out restricted/unrestricted groups
|
||||
@@ -141,9 +138,7 @@ implements OnClickListener, DatabaseListener {
|
||||
Collection<GroupMessageHeader> headers =
|
||||
db.getMessageHeaders(g.getId());
|
||||
// Display the headers in the UI
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, g, headers);
|
||||
latches.add(latch);
|
||||
displayHeaders(g, headers);
|
||||
} catch(NoSuchSubscriptionException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Subscription removed");
|
||||
@@ -152,39 +147,33 @@ implements OnClickListener, DatabaseListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Full load took " + duration + " ms");
|
||||
// Wait for the headers to be displayed in the UI
|
||||
for(CountDownLatch latch : latches) latch.await();
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayHeaders(final CountDownLatch latch, final Group g,
|
||||
private void displayHeaders(final Group g,
|
||||
final Collection<GroupMessageHeader> headers) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Remove the old item, if any
|
||||
GroupListItem item = findGroup(g.getId());
|
||||
if(item != null) adapter.remove(item);
|
||||
// Add a new item if there are any headers to display
|
||||
if(!headers.isEmpty()) {
|
||||
List<GroupMessageHeader> headerList =
|
||||
new ArrayList<GroupMessageHeader>(headers);
|
||||
adapter.add(new GroupListItem(g, headerList));
|
||||
adapter.sort(GroupComparator.INSTANCE);
|
||||
}
|
||||
selectFirstUnread();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
// Remove the old item, if any
|
||||
GroupListItem item = findGroup(g.getId());
|
||||
if(item != null) adapter.remove(item);
|
||||
// Add a new item if there are any headers to display
|
||||
if(!headers.isEmpty()) {
|
||||
List<GroupMessageHeader> headerList =
|
||||
new ArrayList<GroupMessageHeader>(headers);
|
||||
adapter.add(new GroupListItem(g, headerList));
|
||||
adapter.sort(GroupComparator.INSTANCE);
|
||||
}
|
||||
selectFirstUnread();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -241,7 +230,7 @@ implements OnClickListener, DatabaseListener {
|
||||
}
|
||||
} else if(e instanceof MessageExpiredEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
||||
loadHeaders(); // FIXME: Don't reload everything
|
||||
loadHeaders();
|
||||
} else if(e instanceof SubscriptionRemovedEvent) {
|
||||
// Reload the group, expecting NoSuchSubscriptionException
|
||||
Group g = ((SubscriptionRemovedEvent) e).getGroup();
|
||||
@@ -263,9 +252,7 @@ implements OnClickListener, DatabaseListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Partial load took " + duration + " ms");
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, g, headers);
|
||||
latch.await();
|
||||
displayHeaders(g, headers);
|
||||
} catch(NoSuchSubscriptionException e) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
|
||||
removeGroup(g.getId());
|
||||
@@ -274,7 +261,7 @@ implements OnClickListener, DatabaseListener {
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import net.sf.briar.android.widgets.HorizontalBorder;
|
||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||
import net.sf.briar.api.AuthorId;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchMessageException;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
@@ -72,7 +72,7 @@ implements OnClickListener {
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
private volatile MessageId messageId = null;
|
||||
private volatile AuthorId authorId = null;
|
||||
|
||||
@@ -234,7 +234,7 @@ implements OnClickListener {
|
||||
}
|
||||
|
||||
private void setReadInDatabase(final boolean read) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
@@ -263,7 +263,7 @@ implements OnClickListener {
|
||||
}
|
||||
|
||||
private void loadMessageBody() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
@@ -329,7 +329,7 @@ implements OnClickListener {
|
||||
}
|
||||
|
||||
private void setRatingInDatabase(final Rating r) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
|
||||
@@ -17,14 +17,17 @@ import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.R;
|
||||
import net.sf.briar.android.AuthorNameComparator;
|
||||
import net.sf.briar.android.BriarActivity;
|
||||
import net.sf.briar.android.BriarService;
|
||||
import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.android.LocalAuthorNameSpinnerAdapter;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import net.sf.briar.android.widgets.HorizontalSpace;
|
||||
import net.sf.briar.api.LocalAuthor;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.messaging.Group;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
@@ -47,7 +50,7 @@ import android.widget.TextView;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class WriteGroupMessageActivity extends BriarActivity
|
||||
implements OnClickListener, OnItemSelectedListener {
|
||||
implements OnItemSelectedListener, OnClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(WriteGroupMessageActivity.class.getName());
|
||||
@@ -56,16 +59,18 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
new BriarServiceConnection();
|
||||
|
||||
@Inject private BundleEncrypter bundleEncrypter;
|
||||
private GroupNameSpinnerAdapter adapter = null;
|
||||
private Spinner spinner = null;
|
||||
private LocalAuthorNameSpinnerAdapter fromAdapter = null;
|
||||
private GroupNameSpinnerAdapter toAdapter = null;
|
||||
private Spinner fromSpinner = null, toSpinner = null;
|
||||
private ImageButton sendButton = null;
|
||||
private EditText content = null;
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
@Inject private volatile MessageFactory messageFactory;
|
||||
private volatile boolean restricted = false;
|
||||
private volatile LocalAuthor localAuthor = null;
|
||||
private volatile Group group = null;
|
||||
private volatile GroupId groupId = null;
|
||||
private volatile MessageId parentId = null;
|
||||
@@ -85,33 +90,51 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
layout.setOrientation(VERTICAL);
|
||||
|
||||
LinearLayout actionBar = new LinearLayout(this);
|
||||
actionBar.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
actionBar.setOrientation(HORIZONTAL);
|
||||
actionBar.setGravity(CENTER_VERTICAL);
|
||||
LinearLayout header = new LinearLayout(this);
|
||||
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
header.setOrientation(HORIZONTAL);
|
||||
header.setGravity(CENTER_VERTICAL);
|
||||
|
||||
TextView from = new TextView(this);
|
||||
from.setTextSize(18);
|
||||
from.setPadding(10, 10, 10, 10);
|
||||
from.setText(R.string.from);
|
||||
header.addView(from);
|
||||
|
||||
fromAdapter = new LocalAuthorNameSpinnerAdapter(this);
|
||||
fromSpinner = new Spinner(this);
|
||||
fromSpinner.setOnItemSelectedListener(this);
|
||||
loadLocalAuthorList();
|
||||
header.addView(fromSpinner);
|
||||
|
||||
header.addView(new HorizontalSpace(this));
|
||||
|
||||
sendButton = new ImageButton(this);
|
||||
sendButton.setBackgroundResource(0);
|
||||
sendButton.setImageResource(R.drawable.social_send_now);
|
||||
sendButton.setEnabled(false); // Enabled when a group is selected
|
||||
sendButton.setOnClickListener(this);
|
||||
header.addView(sendButton);
|
||||
layout.addView(header);
|
||||
|
||||
header = new LinearLayout(this);
|
||||
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
header.setOrientation(HORIZONTAL);
|
||||
header.setGravity(CENTER_VERTICAL);
|
||||
|
||||
TextView to = new TextView(this);
|
||||
to.setTextSize(18);
|
||||
to.setPadding(10, 10, 10, 10);
|
||||
to.setText(R.string.to);
|
||||
actionBar.addView(to);
|
||||
header.addView(to);
|
||||
|
||||
adapter = new GroupNameSpinnerAdapter(this);
|
||||
spinner = new Spinner(this);
|
||||
spinner.setAdapter(adapter);
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
toAdapter = new GroupNameSpinnerAdapter(this);
|
||||
toSpinner = new Spinner(this);
|
||||
toSpinner.setAdapter(toAdapter);
|
||||
toSpinner.setOnItemSelectedListener(this);
|
||||
loadGroupList();
|
||||
actionBar.addView(spinner);
|
||||
|
||||
actionBar.addView(new HorizontalSpace(this));
|
||||
|
||||
sendButton = new ImageButton(this);
|
||||
sendButton.setBackgroundResource(0);
|
||||
sendButton.setImageResource(R.drawable.social_send_now);
|
||||
sendButton.setEnabled(false);
|
||||
sendButton.setOnClickListener(this);
|
||||
actionBar.addView(sendButton);
|
||||
layout.addView(actionBar);
|
||||
header.addView(toSpinner);
|
||||
layout.addView(header);
|
||||
|
||||
content = new EditText(this);
|
||||
content.setPadding(10, 10, 10, 10);
|
||||
@@ -128,20 +151,48 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
serviceConnection, 0);
|
||||
}
|
||||
|
||||
// FIXME: If restricted, only load groups the user can post to
|
||||
private void loadGroupList() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
private void loadLocalAuthorList() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
List<Group> postable = new ArrayList<Group>();
|
||||
updateLocalAuthorList(db.getLocalAuthors());
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateLocalAuthorList(
|
||||
final Collection<LocalAuthor> localAuthors) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
fromAdapter.clear();
|
||||
for(LocalAuthor a : localAuthors) fromAdapter.add(a);
|
||||
fromAdapter.sort(AuthorNameComparator.INSTANCE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadGroupList() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
List<Group> groups = new ArrayList<Group>();
|
||||
if(restricted) {
|
||||
postable.addAll(db.getLocalGroups());
|
||||
groups.addAll(db.getLocalGroups());
|
||||
} else {
|
||||
for(Group g : db.getSubscriptions())
|
||||
if(!g.isRestricted()) postable.add(g);
|
||||
if(!g.isRestricted()) groups.add(g);
|
||||
}
|
||||
updateGroupList(Collections.unmodifiableList(postable));
|
||||
groups = Collections.unmodifiableList(groups);
|
||||
updateGroupList(groups);
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
@@ -156,13 +207,15 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
private void updateGroupList(final Collection<Group> groups) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
int index = -1;
|
||||
for(Group g : groups) {
|
||||
if(g.getId().equals(groupId)) {
|
||||
group = g;
|
||||
spinner.setSelection(adapter.getCount());
|
||||
index = toAdapter.getCount();
|
||||
}
|
||||
adapter.add(g);
|
||||
toAdapter.add(g);
|
||||
}
|
||||
if(index != -1) toSpinner.setSelection(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -180,21 +233,45 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
unbindService(serviceConnection);
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
if(parent == fromSpinner) {
|
||||
localAuthor = fromAdapter.getItem(position);
|
||||
} else if(parent == toSpinner) {
|
||||
group = toAdapter.getItem(position);
|
||||
groupId = group.getId();
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
if(parent == fromSpinner) {
|
||||
localAuthor = null;
|
||||
} else if(parent == toSpinner) {
|
||||
group = null;
|
||||
groupId = null;
|
||||
sendButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if(group == null) throw new IllegalStateException();
|
||||
try {
|
||||
storeMessage(content.getText().toString().getBytes("UTF-8"));
|
||||
storeMessage(localAuthor, group,
|
||||
content.getText().toString().getBytes("UTF-8"));
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private void storeMessage(final byte[] body) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
private void storeMessage(final LocalAuthor localAuthor, final Group group,
|
||||
final byte[] body) {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
// FIXME: Anonymous/pseudonymous, restricted/unrestricted
|
||||
Message m = messageFactory.createAnonymousMessage(parentId,
|
||||
group, "text/plain", body);
|
||||
db.addLocalGroupMessage(m);
|
||||
@@ -213,17 +290,4 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
group = adapter.getItem(position);
|
||||
groupId = group.getId();
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
group = null;
|
||||
groupId = null;
|
||||
sendButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,42 @@
|
||||
package net.sf.briar.android.invitation;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.android.AuthorNameComparator;
|
||||
import net.sf.briar.android.BriarActivity;
|
||||
import net.sf.briar.android.BriarService;
|
||||
import net.sf.briar.android.BriarService.BriarServiceConnection;
|
||||
import net.sf.briar.api.AuthorId;
|
||||
import net.sf.briar.api.LocalAuthor;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.android.ReferenceManager;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.invitation.InvitationListener;
|
||||
import net.sf.briar.api.invitation.InvitationState;
|
||||
import net.sf.briar.api.invitation.InvitationTask;
|
||||
import net.sf.briar.api.invitation.InvitationTaskFactory;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class AddContactActivity extends BriarActivity
|
||||
implements InvitationListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AddContactActivity.class.getName());
|
||||
|
||||
private final BriarServiceConnection serviceConnection =
|
||||
new BriarServiceConnection();
|
||||
|
||||
@Inject private BundleEncrypter bundleEncrypter;
|
||||
@Inject private CryptoComponent crypto;
|
||||
@Inject private InvitationTaskFactory invitationTaskFactory;
|
||||
@@ -33,6 +54,10 @@ implements InvitationListener {
|
||||
private boolean localMatched = false, remoteMatched = false;
|
||||
private String contactName = null;
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(null);
|
||||
@@ -105,6 +130,10 @@ implements InvitationListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bind to the service so we can wait for the DB to be opened
|
||||
bindService(new Intent(BriarService.class.getName()),
|
||||
serviceConnection, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,6 +185,34 @@ implements InvitationListener {
|
||||
setView(view);
|
||||
}
|
||||
|
||||
void loadLocalAuthorList(final ArrayAdapter<LocalAuthor> adapter) {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
updateLocalAuthorList(adapter, db.getLocalAuthors());
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateLocalAuthorList(final ArrayAdapter<LocalAuthor> adapter,
|
||||
final Collection<LocalAuthor> localAuthors) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
adapter.clear();
|
||||
for(LocalAuthor a : localAuthors) adapter.add(a);
|
||||
adapter.sort(AuthorNameComparator.INSTANCE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setLocalAuthorId(AuthorId localAuthorId) {
|
||||
this.localAuthorId = localAuthorId;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ abstract class AddContactView extends LinearLayout {
|
||||
|
||||
protected AddContactActivity container = null;
|
||||
|
||||
AddContactView(Context context) {
|
||||
super(context);
|
||||
AddContactView(Context ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
void init(AddContactActivity container) {
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
package net.sf.briar.android.invitation;
|
||||
|
||||
import static android.view.Gravity.CENTER;
|
||||
import net.sf.briar.R;
|
||||
import net.sf.briar.android.LocalAuthorNameSpinnerAdapter;
|
||||
import net.sf.briar.android.widgets.CommonLayoutParams;
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class NetworkSetupView extends AddContactView
|
||||
implements WifiStateListener, BluetoothStateListener, OnClickListener {
|
||||
implements WifiStateListener, BluetoothStateListener, OnItemSelectedListener,
|
||||
OnClickListener {
|
||||
|
||||
private LocalAuthorNameSpinnerAdapter adapter = null;
|
||||
private Spinner spinner = null;
|
||||
private Button continueButton = null;
|
||||
|
||||
NetworkSetupView(Context ctx) {
|
||||
@@ -20,13 +29,25 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
|
||||
void populate() {
|
||||
removeAllViews();
|
||||
Context ctx = getContext();
|
||||
TextView chooseIdentity = new TextView(ctx);
|
||||
chooseIdentity.setTextSize(14);
|
||||
chooseIdentity.setPadding(10, 10, 10, 10);
|
||||
chooseIdentity.setText(R.string.choose_identity);
|
||||
addView(chooseIdentity);
|
||||
|
||||
// FIXME: Add a spinner for choosing which identity to use
|
||||
LinearLayout innerLayout = new LinearLayout(ctx);
|
||||
innerLayout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
innerLayout.setOrientation(HORIZONTAL);
|
||||
innerLayout.setGravity(CENTER);
|
||||
|
||||
TextView yourIdentity = new TextView(ctx);
|
||||
yourIdentity.setTextSize(18);
|
||||
yourIdentity.setPadding(10, 10, 10, 10);
|
||||
yourIdentity.setText(R.string.your_identity);
|
||||
innerLayout.addView(yourIdentity);
|
||||
|
||||
adapter = new LocalAuthorNameSpinnerAdapter(ctx);
|
||||
spinner = new Spinner(ctx);
|
||||
spinner.setAdapter(adapter);
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
container.loadLocalAuthorList(adapter);
|
||||
innerLayout.addView(spinner);
|
||||
addView(innerLayout);
|
||||
|
||||
WifiWidget wifi = new WifiWidget(ctx);
|
||||
wifi.init(this);
|
||||
@@ -70,8 +91,16 @@ implements WifiStateListener, BluetoothStateListener, OnClickListener {
|
||||
else continueButton.setEnabled(false);
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
container.setLocalAuthorId(adapter.getItem(position).getId());
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
container.setLocalAuthorId(null);
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
// Continue
|
||||
container.setView(new InvitationCodeView(container));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -118,10 +117,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Load took " + duration + " ms");
|
||||
// Wait for the headers to be displayed in the UI
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, headers);
|
||||
latch.await();
|
||||
// Display the headers in the UI
|
||||
displayHeaders(headers);
|
||||
} catch(NoSuchContactException e) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Contact removed");
|
||||
finishOnUiThread();
|
||||
@@ -130,25 +127,21 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayHeaders(final CountDownLatch latch,
|
||||
private void displayHeaders(
|
||||
final Collection<PrivateMessageHeader> headers) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
adapter.clear();
|
||||
for(PrivateMessageHeader h : headers) adapter.add(h);
|
||||
adapter.sort(AscendingHeaderComparator.INSTANCE);
|
||||
selectFirstUnread();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
adapter.clear();
|
||||
for(PrivateMessageHeader h : headers) adapter.add(h);
|
||||
adapter.sort(AscendingHeaderComparator.INSTANCE);
|
||||
selectFirstUnread();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -199,7 +192,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
|
||||
}
|
||||
} else if(e instanceof MessageExpiredEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
||||
loadHeaders(); // FIXME: Don't reload everything
|
||||
loadHeaders();
|
||||
} else if(e instanceof PrivateMessageAddedEvent) {
|
||||
PrivateMessageAddedEvent p = (PrivateMessageAddedEvent) e;
|
||||
if(p.getContactId().equals(contactId)) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -102,8 +101,6 @@ implements OnClickListener, DatabaseListener {
|
||||
// Wait for the service to be bound and started
|
||||
serviceConnection.waitForStartup();
|
||||
// Load the contact list from the database
|
||||
Collection<CountDownLatch> latches =
|
||||
new ArrayList<CountDownLatch>();
|
||||
long now = System.currentTimeMillis();
|
||||
for(Contact c : db.getContacts()) {
|
||||
try {
|
||||
@@ -111,9 +108,7 @@ implements OnClickListener, DatabaseListener {
|
||||
Collection<PrivateMessageHeader> headers =
|
||||
db.getPrivateMessageHeaders(c.getId());
|
||||
// Display the headers in the UI
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, c, headers);
|
||||
latches.add(latch);
|
||||
displayHeaders(c, headers);
|
||||
} catch(NoSuchContactException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Contact removed");
|
||||
@@ -122,39 +117,33 @@ implements OnClickListener, DatabaseListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Full load took " + duration + " ms");
|
||||
// Wait for the headers to be displayed in the UI
|
||||
for(CountDownLatch latch : latches) latch.await();
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayHeaders(final CountDownLatch latch, final Contact c,
|
||||
private void displayHeaders(final Contact c,
|
||||
final Collection<PrivateMessageHeader> headers) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// Remove the old item, if any
|
||||
ConversationListItem item = findConversation(c.getId());
|
||||
if(item != null) adapter.remove(item);
|
||||
// Add a new item if there are any headers to display
|
||||
if(!headers.isEmpty()) {
|
||||
List<PrivateMessageHeader> headerList =
|
||||
new ArrayList<PrivateMessageHeader>(headers);
|
||||
adapter.add(new ConversationListItem(c, headerList));
|
||||
adapter.sort(ConversationComparator.INSTANCE);
|
||||
}
|
||||
selectFirstUnread();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
// Remove the old item, if any
|
||||
ConversationListItem item = findConversation(c.getId());
|
||||
if(item != null) adapter.remove(item);
|
||||
// Add a new item if there are any headers to display
|
||||
if(!headers.isEmpty()) {
|
||||
List<PrivateMessageHeader> headerList =
|
||||
new ArrayList<PrivateMessageHeader>(headers);
|
||||
adapter.add(new ConversationListItem(c, headerList));
|
||||
adapter.sort(ConversationComparator.INSTANCE);
|
||||
}
|
||||
selectFirstUnread();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -203,7 +192,7 @@ implements OnClickListener, DatabaseListener {
|
||||
loadHeaders(((ContactRemovedEvent) e).getContactId());
|
||||
} else if(e instanceof MessageExpiredEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
|
||||
loadHeaders(); // FIXME: Don't reload everything
|
||||
loadHeaders();
|
||||
} else if(e instanceof PrivateMessageAddedEvent) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
|
||||
loadHeaders(((PrivateMessageAddedEvent) e).getContactId());
|
||||
@@ -222,9 +211,7 @@ implements OnClickListener, DatabaseListener {
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Partial load took " + duration + " ms");
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
displayHeaders(latch, contact, headers);
|
||||
latch.await();
|
||||
displayHeaders(contact, headers);
|
||||
} catch(NoSuchContactException e) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Contact removed");
|
||||
removeConversation(c);
|
||||
@@ -233,7 +220,7 @@ implements OnClickListener, DatabaseListener {
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Interrupted while loading headers");
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ 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.BundleEncrypter;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchMessageException;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
@@ -61,7 +61,7 @@ implements OnClickListener {
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
private volatile MessageId messageId = null;
|
||||
|
||||
@Override
|
||||
@@ -187,7 +187,7 @@ implements OnClickListener {
|
||||
}
|
||||
|
||||
private void setReadInDatabase(final boolean read) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
@@ -216,7 +216,7 @@ implements OnClickListener {
|
||||
}
|
||||
|
||||
private void loadMessageBody() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
|
||||
@@ -19,11 +19,13 @@ 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.HorizontalSpace;
|
||||
import net.sf.briar.api.AuthorId;
|
||||
import net.sf.briar.api.Contact;
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.LocalAuthor;
|
||||
import net.sf.briar.api.android.BundleEncrypter;
|
||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DatabaseExecutor;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageFactory;
|
||||
@@ -44,7 +46,7 @@ import android.widget.TextView;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class WritePrivateMessageActivity extends BriarActivity
|
||||
implements OnClickListener, OnItemSelectedListener {
|
||||
implements OnItemSelectedListener, OnClickListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(WritePrivateMessageActivity.class.getName());
|
||||
@@ -53,6 +55,7 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
new BriarServiceConnection();
|
||||
|
||||
@Inject private BundleEncrypter bundleEncrypter;
|
||||
private TextView from = null;
|
||||
private ContactNameSpinnerAdapter adapter = null;
|
||||
private Spinner spinner = null;
|
||||
private ImageButton sendButton = null;
|
||||
@@ -60,8 +63,9 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
|
||||
// Fields that are accessed from DB threads must be volatile
|
||||
@Inject private volatile DatabaseComponent db;
|
||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||
@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
|
||||
@Inject private volatile MessageFactory messageFactory;
|
||||
private volatile LocalAuthor localAuthor = null;
|
||||
private volatile ContactId contactId = null;
|
||||
private volatile MessageId parentId = null;
|
||||
|
||||
@@ -79,33 +83,46 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
layout.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
layout.setOrientation(VERTICAL);
|
||||
|
||||
LinearLayout actionBar = new LinearLayout(this);
|
||||
actionBar.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
actionBar.setOrientation(HORIZONTAL);
|
||||
actionBar.setGravity(CENTER_VERTICAL);
|
||||
LinearLayout header = new LinearLayout(this);
|
||||
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
header.setOrientation(HORIZONTAL);
|
||||
header.setGravity(CENTER_VERTICAL);
|
||||
|
||||
from = new TextView(this);
|
||||
from.setTextSize(18);
|
||||
from.setMaxLines(1);
|
||||
from.setPadding(10, 10, 10, 10);
|
||||
from.setText(R.string.from);
|
||||
header.addView(from);
|
||||
|
||||
header.addView(new HorizontalSpace(this));
|
||||
|
||||
sendButton = new ImageButton(this);
|
||||
sendButton.setBackgroundResource(0);
|
||||
sendButton.setImageResource(R.drawable.social_send_now);
|
||||
sendButton.setEnabled(false); // Enabled after loading the local author
|
||||
sendButton.setOnClickListener(this);
|
||||
header.addView(sendButton);
|
||||
layout.addView(header);
|
||||
|
||||
header = new LinearLayout(this);
|
||||
header.setLayoutParams(CommonLayoutParams.MATCH_WRAP);
|
||||
header.setOrientation(HORIZONTAL);
|
||||
header.setGravity(CENTER_VERTICAL);
|
||||
|
||||
TextView to = new TextView(this);
|
||||
to.setTextSize(18);
|
||||
to.setPadding(10, 10, 10, 10);
|
||||
to.setText(R.string.to);
|
||||
actionBar.addView(to);
|
||||
header.addView(to);
|
||||
|
||||
adapter = new ContactNameSpinnerAdapter(this);
|
||||
spinner = new Spinner(this);
|
||||
spinner.setAdapter(adapter);
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
loadContactList();
|
||||
actionBar.addView(spinner);
|
||||
|
||||
actionBar.addView(new HorizontalSpace(this));
|
||||
|
||||
sendButton = new ImageButton(this);
|
||||
sendButton.setBackgroundResource(0);
|
||||
sendButton.setImageResource(R.drawable.social_send_now);
|
||||
sendButton.setEnabled(false);
|
||||
sendButton.setOnClickListener(this);
|
||||
actionBar.addView(sendButton);
|
||||
layout.addView(actionBar);
|
||||
header.addView(spinner);
|
||||
layout.addView(header);
|
||||
|
||||
content = new EditText(this);
|
||||
content.setPadding(10, 10, 10, 10);
|
||||
@@ -123,7 +140,7 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
}
|
||||
|
||||
private void loadContactList() {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
@@ -142,11 +159,12 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
private void updateContactList(final Collection<Contact> contacts) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
int index = -1;
|
||||
for(Contact c : contacts) {
|
||||
if(c.getId().equals(contactId))
|
||||
spinner.setSelection(adapter.getCount());
|
||||
if(c.getId().equals(contactId)) index = adapter.getCount();
|
||||
adapter.add(c);
|
||||
}
|
||||
if(index != -1) spinner.setSelection(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -164,18 +182,55 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
unbindService(serviceConnection);
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
Contact c = adapter.getItem(position);
|
||||
loadLocalAuthor(c.getLocalAuthorId());
|
||||
contactId = c.getId();
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
contactId = null;
|
||||
sendButton.setEnabled(false);
|
||||
}
|
||||
|
||||
private void loadLocalAuthor(final AuthorId a) {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
localAuthor = db.getLocalAuthor(a);
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
});
|
||||
} catch(DbException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
} catch(InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
if(contactId == null) throw new IllegalStateException();
|
||||
if(localAuthor == null || contactId == null)
|
||||
throw new IllegalStateException();
|
||||
try {
|
||||
storeMessage(content.getText().toString().getBytes("UTF-8"));
|
||||
storeMessage(localAuthor, contactId,
|
||||
content.getText().toString().getBytes("UTF-8"));
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private void storeMessage(final byte[] body) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
private void storeMessage(final LocalAuthor localAuthor,
|
||||
final ContactId contactId, final byte[] body) {
|
||||
dbUiExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
serviceConnection.waitForStartup();
|
||||
@@ -197,15 +252,4 @@ implements OnClickListener, OnItemSelectedListener {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
contactId = adapter.getItem(position).getId();
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
contactId = null;
|
||||
sendButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ public class Contact {
|
||||
|
||||
private final ContactId id;
|
||||
private final Author author;
|
||||
private final AuthorId localAuthorId;
|
||||
private final long lastConnected;
|
||||
|
||||
public Contact(ContactId id, Author author, long lastConnected) {
|
||||
public Contact(ContactId id, Author author, AuthorId localAuthorId,
|
||||
long lastConnected) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.localAuthorId = localAuthorId;
|
||||
this.lastConnected = lastConnected;
|
||||
}
|
||||
|
||||
@@ -20,6 +23,10 @@ public class Contact {
|
||||
return author;
|
||||
}
|
||||
|
||||
public AuthorId getLocalAuthorId() {
|
||||
return localAuthorId;
|
||||
}
|
||||
|
||||
public long getLastConnected() {
|
||||
return lastConnected;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
package net.sf.briar.api.db.event;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
|
||||
/**
|
||||
* An event that is broadcast when one or messages expire from the database,
|
||||
* potentially changing the database's retention time.
|
||||
*/
|
||||
public class MessageExpiredEvent extends DatabaseEvent {
|
||||
|
||||
private final Collection<MessageId> expired;
|
||||
|
||||
public MessageExpiredEvent(Collection<MessageId> expired) {
|
||||
this.expired = expired;
|
||||
}
|
||||
|
||||
public Collection<MessageId> getMessageIds() {
|
||||
return expired;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2045,9 +2045,8 @@ DatabaseCleaner.Callback {
|
||||
while(freeSpace < MIN_FREE_SPACE) {
|
||||
boolean expired = expireMessages(BYTES_PER_SWEEP);
|
||||
if(freeSpace < CRITICAL_FREE_SPACE && !expired) {
|
||||
// FIXME: Work out what to do here - the amount of free space
|
||||
// is critically low and there are no messages left to expire
|
||||
throw new Error("Disk space is critical");
|
||||
// FIXME: Work out what to do here
|
||||
throw new Error("Disk space is critically low");
|
||||
}
|
||||
Thread.yield();
|
||||
freeSpace = db.getFreeSpace();
|
||||
@@ -2086,7 +2085,7 @@ DatabaseCleaner.Callback {
|
||||
messageLock.writeLock().unlock();
|
||||
}
|
||||
if(expired.isEmpty()) return false;
|
||||
callListeners(new MessageExpiredEvent(expired));
|
||||
callListeners(new MessageExpiredEvent());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1155,7 +1155,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT authorId, name, publicKey, lastConnected"
|
||||
String sql = "SELECT authorId, name, publicKey, localAuthorId,"
|
||||
+ " lastConnected"
|
||||
+ " FROM contacts AS c"
|
||||
+ " JOIN connectionTimes AS ct"
|
||||
+ " ON c.contactId = ct.contactId"
|
||||
@@ -1167,11 +1168,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(1));
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
long lastConnected = rs.getLong(4);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(4));
|
||||
long lastConnected = rs.getLong(5);
|
||||
rs.close();
|
||||
ps.close();
|
||||
Author author = new Author(authorId, name, publicKey);
|
||||
return new Contact(c, author, lastConnected);
|
||||
return new Contact(c, author, localAuthorId, lastConnected);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
@@ -1205,7 +1207,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT c.contactId, authorId, name, publicKey,"
|
||||
+ " lastConnected"
|
||||
+ " localAuthorId, lastConnected"
|
||||
+ " FROM contacts AS c"
|
||||
+ " JOIN connectionTimes AS ct"
|
||||
+ " ON c.contactId = ct.contactId";
|
||||
@@ -1217,9 +1219,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(2));
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
long lastConnected = rs.getLong(5);
|
||||
AuthorId localAuthorId = new AuthorId(rs.getBytes(5));
|
||||
long lastConnected = rs.getLong(6);
|
||||
Author author = new Author(authorId, name, publicKey);
|
||||
contacts.add(new Contact(contactId, author, lastConnected));
|
||||
contacts.add(new Contact(contactId, author, localAuthorId,
|
||||
lastConnected));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
|
||||
@@ -134,6 +134,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
|
||||
} else if(now >= creationTime) {
|
||||
incomingNew.put(k, s);
|
||||
} else {
|
||||
// FIXME: Work out what to do here
|
||||
throw new Error("Clock has moved backwards");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
transportProperties = new TransportProperties(Collections.singletonMap(
|
||||
"foo", "bar"));
|
||||
contactId = new ContactId(234);
|
||||
contact = new Contact(contactId, author, timestamp);
|
||||
contact = new Contact(contactId, author, localAuthorId, timestamp);
|
||||
endpoint = new Endpoint(contactId, transportId, 123, true);
|
||||
temporarySecret = new TemporarySecret(contactId, transportId, 123,
|
||||
false, 234, new byte[32], 345, 456, new byte[4]);
|
||||
|
||||
Reference in New Issue
Block a user