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