Compare commits

...

2 Commits

Author SHA1 Message Date
akwizgran
21d6dfe817 Add transactional helper methods to DbViewModel. 2021-01-26 14:52:25 +00:00
akwizgran
c1e83b22c1 Add helper method for running a DB task and logging any exception it throws. 2021-01-26 13:51:03 +00:00
24 changed files with 321 additions and 433 deletions

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api;
public interface ThrowingRunnable<T extends Throwable> {
void run() throws T;
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.sync; package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.sync; package org.briarproject.bramble.sync;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.sync;
interface ThrowingRunnable<T extends Throwable> {
void run() throws T;
}

View File

@@ -45,10 +45,8 @@ import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
@@ -173,14 +171,9 @@ class ContactListViewModel extends DbViewModel implements EventListener {
} }
void checkForPendingContacts() { void checkForPendingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { boolean hasPending = !contactManager.getPendingContacts().isEmpty();
boolean hasPending = hasPendingContacts.postValue(hasPending);
!contactManager.getPendingContacts().isEmpty();
hasPendingContacts.postValue(hasPending);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -2,12 +2,9 @@ package org.briarproject.briar.android.contact.add.remote;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchPendingContactException; import org.briarproject.bramble.api.db.NoSuchPendingContactException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -18,7 +15,6 @@ import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.android.viewmodel.LiveResult;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import java.security.GeneralSecurityException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -66,15 +62,10 @@ public class AddContactViewModel extends DbViewModel {
} }
private void loadHandshakeLink() { private void loadHandshakeLink() {
runOnDbThread(() -> { // If an exception is thrown the UI should stay disabled,
try { // leaving the user unable to proceed
handshakeLink.postValue(contactManager.getHandshakeLink()); runOnDbThreadOrLogException(() ->
} catch (DbException e) { handshakeLink.postValue(contactManager.getHandshakeLink()));
logException(LOG, WARNING, e);
// the UI should stay disabled in this case,
// leaving the user unable to proceed
}
});
} }
LiveData<String> getHandshakeLink() { LiveData<String> getHandshakeLink() {
@@ -106,17 +97,11 @@ public class AddContactViewModel extends DbViewModel {
void addContact(String nickname) { void addContact(String nickname) {
if (remoteHandshakeLink == null) throw new IllegalStateException(); if (remoteHandshakeLink == null) throw new IllegalStateException();
runOnDbThread(() -> { runOnDbThread(() -> {
try { contactManager.addPendingContact(remoteHandshakeLink, nickname);
contactManager.addPendingContact(remoteHandshakeLink, nickname); addContactResult.postValue(new LiveResult<>(true));
addContactResult.postValue(new LiveResult<>(true)); }, e -> {
} catch (UnsupportedVersionException e) { logException(LOG, WARNING, e);
logException(LOG, WARNING, e); addContactResult.postValue(new LiveResult<>(e));
addContactResult.postValue(new LiveResult<>(e));
} catch (DbException | FormatException
| GeneralSecurityException e) {
logException(LOG, WARNING, e);
addContactResult.postValue(new LiveResult<>(e));
}
}); });
} }
@@ -126,13 +111,13 @@ public class AddContactViewModel extends DbViewModel {
public void updatePendingContact(String name, PendingContact p) { public void updatePendingContact(String name, PendingContact p) {
runOnDbThread(() -> { runOnDbThread(() -> {
try { contactManager.removePendingContact(p.getId());
contactManager.removePendingContact(p.getId()); addContact(name);
addContact(name); }, e -> {
} catch (NoSuchPendingContactException e) { if (e instanceof NoSuchPendingContactException) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
// no error in UI as pending contact was converted into contact // no error in UI as pending contact was converted into contact
} catch (DbException e) { } else {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
addContactResult.postValue(new LiveResult<>(e)); addContactResult.postValue(new LiveResult<>(e));
} }

View File

@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent; import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent; import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -33,10 +32,8 @@ import javax.inject.Inject;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.contact.PendingContactState.OFFLINE; import static org.briarproject.bramble.api.contact.PendingContactState.OFFLINE;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault @NotNullByDefault
public class PendingContactListViewModel extends DbViewModel public class PendingContactListViewModel extends DbViewModel
@@ -90,24 +87,20 @@ public class PendingContactListViewModel extends DbViewModel
} }
private void loadPendingContacts() { private void loadPendingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Collection<Pair<PendingContact, PendingContactState>> pairs =
Collection<Pair<PendingContact, PendingContactState>> pairs = contactManager.getPendingContacts();
contactManager.getPendingContacts(); List<PendingContactItem> items = new ArrayList<>(pairs.size());
List<PendingContactItem> items = new ArrayList<>(pairs.size()); boolean online = pairs.isEmpty();
boolean online = pairs.isEmpty(); for (Pair<PendingContact, PendingContactState> pair : pairs) {
for (Pair<PendingContact, PendingContactState> pair : pairs) { PendingContact p = pair.getFirst();
PendingContact p = pair.getFirst(); PendingContactState state = pair.getSecond();
PendingContactState state = pair.getSecond(); long lastPoll = rendezvousPoller.getLastPollTime(p.getId());
long lastPoll = rendezvousPoller.getLastPollTime(p.getId()); items.add(new PendingContactItem(p, state, lastPoll));
items.add(new PendingContactItem(p, state, lastPoll)); online = online || state != OFFLINE;
online = online || state != OFFLINE;
}
pendingContacts.postValue(items);
hasInternetConnection.postValue(online);
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
pendingContacts.postValue(items);
hasInternetConnection.postValue(online);
}); });
} }
@@ -116,13 +109,8 @@ public class PendingContactListViewModel extends DbViewModel
} }
void removePendingContact(PendingContactId id) { void removePendingContact(PendingContactId id) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { contactManager.removePendingContact(id));
contactManager.removePendingContact(id);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
LiveData<Boolean> getHasInternetConnection() { LiveData<Boolean> getHasInternetConnection() {

View File

@@ -149,7 +149,7 @@ public class ConversationViewModel extends DbViewModel
AttachmentReceivedEvent a = (AttachmentReceivedEvent) e; AttachmentReceivedEvent a = (AttachmentReceivedEvent) e;
if (a.getContactId().equals(contactId)) { if (a.getContactId().equals(contactId)) {
LOG.info("Attachment received"); LOG.info("Attachment received");
runOnDbThread(() -> attachmentRetriever runOnDbThreadOrLogException(() -> attachmentRetriever
.loadAttachmentItem(a.getMessageId())); .loadAttachmentItem(a.getMessageId()));
} }
} else if (e instanceof AvatarUpdatedEvent) { } else if (e instanceof AvatarUpdatedEvent) {
@@ -194,44 +194,36 @@ public class ConversationViewModel extends DbViewModel
private void loadContact(ContactId contactId) { private void loadContact(ContactId contactId) {
runOnDbThread(() -> { runOnDbThread(() -> {
try { long start = now();
long start = now(); Contact c = contactManager.getContact(contactId);
Contact c = contactManager.getContact(contactId); AuthorInfo authorInfo = authorManager.getAuthorInfo(c);
AuthorInfo authorInfo = authorManager.getAuthorInfo(c); contactItem.postValue(new ContactItem(c, authorInfo));
contactItem.postValue(new ContactItem(c, authorInfo)); logDuration(LOG, "Loading contact", start);
logDuration(LOG, "Loading contact", start); start = now();
start = now(); checkFeaturesAndOnboarding(contactId);
checkFeaturesAndOnboarding(contactId); logDuration(LOG, "Checking for image support", start);
logDuration(LOG, "Checking for image support", start); }, e -> {
} catch (NoSuchContactException e) { if (e instanceof NoSuchContactException) {
contactDeleted.postValue(true); contactDeleted.postValue(true);
} catch (DbException e) { } else {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
}); });
} }
void markMessageRead(GroupId g, MessageId m) { void markMessageRead(GroupId g, MessageId m) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); messagingManager.setReadFlag(g, m, true);
messagingManager.setReadFlag(g, m, true); logDuration(LOG, "Marking read", start);
logDuration(LOG, "Marking read", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void setContactAlias(String alias) { void setContactAlias(String alias) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { contactManager.setContactAlias(requireNonNull(contactId),
contactManager.setContactAlias(requireNonNull(contactId), alias.isEmpty() ? null : alias);
alias.isEmpty() ? null : alias); loadContact(contactId);
loadContact(contactId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -327,21 +319,17 @@ public class ConversationViewModel extends DbViewModel
@UiThread @UiThread
private void storeMessage(PrivateMessage m) { private void storeMessage(PrivateMessage m) {
attachmentCreator.onAttachmentsSent(m.getMessage().getId()); attachmentCreator.onAttachmentsSent(m.getMessage().getId());
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); messagingManager.addLocalMessage(m);
messagingManager.addLocalMessage(m); logDuration(LOG, "Storing message", start);
logDuration(LOG, "Storing message", start); Message message = m.getMessage();
Message message = m.getMessage(); PrivateMessageHeader h = new PrivateMessageHeader(
PrivateMessageHeader h = new PrivateMessageHeader( message.getId(), message.getGroupId(),
message.getId(), message.getGroupId(), message.getTimestamp(), true, true, false, false,
message.getTimestamp(), true, true, false, false, m.hasText(), m.getAttachmentHeaders());
m.hasText(), m.getAttachmentHeaders()); // TODO add text to cache when available here
// TODO add text to cache when available here addedHeader.postEvent(h);
addedHeader.postEvent(h);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -383,12 +371,7 @@ public class ConversationViewModel extends DbViewModel
@UiThread @UiThread
void recheckFeaturesAndOnboarding(ContactId contactId) { void recheckFeaturesAndOnboarding(ContactId contactId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { checkFeaturesAndOnboarding(contactId));
checkFeaturesAndOnboarding(contactId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
} }

View File

@@ -6,7 +6,6 @@ import android.net.Uri;
import android.view.View; import android.view.View;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -198,14 +197,12 @@ public class ImageViewModel extends DbViewModel implements EventListener {
private void saveImage(AttachmentItem attachment, OutputStreamProvider osp, private void saveImage(AttachmentItem attachment, OutputStreamProvider osp,
@Nullable Runnable afterCopy) { @Nullable Runnable afterCopy) {
runOnDbThread(() -> { runOnDbThread(() -> {
try { Attachment a =
Attachment a = attachmentReader.getAttachment(attachment.getHeader());
attachmentReader.getAttachment(attachment.getHeader()); copyImageFromDb(a, osp, afterCopy);
copyImageFromDb(a, osp, afterCopy); }, e -> {
} catch (DbException e) { logException(LOG, WARNING, e);
logException(LOG, WARNING, e); saveState.postEvent(true);
saveState.postEvent(true);
}
}); });
} }

View File

@@ -40,10 +40,8 @@ import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID; import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
@@ -164,15 +162,11 @@ class ForumListViewModel extends DbViewModel implements EventListener {
} }
void loadForumInvitations() { void loadForumInvitations() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); int available = forumSharingManager.getInvitations().size();
int available = forumSharingManager.getInvitations().size(); logDuration(LOG, "Loading available", start);
logDuration(LOG, "Loading available", start); numInvitations.postValue(available);
numInvitations.postValue(available);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -51,10 +51,8 @@ import androidx.lifecycle.MutableLiveData;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -122,14 +120,8 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
LiveData<Forum> loadForum() { LiveData<Forum> loadForum() {
MutableLiveData<Forum> forum = new MutableLiveData<>(); MutableLiveData<Forum> forum = new MutableLiveData<>();
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forum.postValue(forumManager.getForum(groupId)));
Forum f = forumManager.getForum(groupId);
forum.postValue(f);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
return forum; return forum;
} }
@@ -147,16 +139,12 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
@Override @Override
public void createAndStoreMessage(String text, public void createAndStoreMessage(String text,
@Nullable MessageId parentId) { @Nullable MessageId parentId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { LocalAuthor author = identityManager.getLocalAuthor();
LocalAuthor author = identityManager.getLocalAuthor(); GroupCount count = forumManager.getGroupCount(groupId);
GroupCount count = forumManager.getGroupCount(groupId); long timestamp = max(count.getLatestMsgTime() + 1,
long timestamp = max(count.getLatestMsgTime() + 1, clock.currentTimeMillis());
clock.currentTimeMillis()); createMessage(text, timestamp, parentId, author);
createMessage(text, timestamp, parentId, author);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -171,15 +159,11 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
} }
private void storePost(ForumPost msg, String text) { private void storePost(ForumPost msg, String text) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); ForumPostHeader header = forumManager.addLocalPost(msg);
ForumPostHeader header = forumManager.addLocalPost(msg); addItemAsync(buildItem(header, text));
addItemAsync(buildItem(header, text)); logDuration(LOG, "Storing forum post", start);
logDuration(LOG, "Storing forum post", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -195,39 +179,23 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
@Override @Override
protected void markItemRead(ForumPostItem item) { protected void markItemRead(ForumPostItem item) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forumManager.setReadFlag(groupId, item.getId(), true));
forumManager.setReadFlag(groupId, item.getId(), true);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
public void loadSharingContacts() { public void loadSharingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(true, txn -> {
try { Collection<Contact> contacts =
Collection<Contact> contacts = forumSharingManager.getSharedWith(txn, groupId);
forumSharingManager.getSharedWith(groupId); Collection<ContactId> contactIds = new ArrayList<>(contacts.size());
Collection<ContactId> contactIds = for (Contact c : contacts) contactIds.add(c.getId());
new ArrayList<>(contacts.size()); txn.attach(() -> sharingController.addAll(contactIds));
for (Contact c : contacts) contactIds.add(c.getId());
sharingController.addAll(contactIds);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void deleteForum() { void deleteForum() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { forumManager.removeForum(forumManager.getForum(groupId)));
Forum f = forumManager.getForum(groupId);
forumManager.removeForum(f);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
Toast.makeText(getApplication(), R.string.forum_left_toast, Toast.makeText(getApplication(), R.string.forum_left_toast,
LENGTH_SHORT).show(); LENGTH_SHORT).show();
} }

View File

@@ -3,7 +3,6 @@ package org.briarproject.briar.android.navdrawer;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -66,34 +65,27 @@ public class NavDrawerViewModel extends DbViewModel {
@UiThread @UiThread
void checkExpiryWarning() { void checkExpiryWarning() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings = int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0);
settingsManager.getSettings(SETTINGS_NAMESPACE);
int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0);
if (warningInt == 0) { if (warningInt == 0) {
// we have not warned before // we have not warned before
showExpiryWarning.postValue(true);
} else {
long warningLong = warningInt * 1000L;
long now = System.currentTimeMillis();
long daysSinceLastWarning =
(now - warningLong) / DAYS.toMillis(1);
long daysBeforeExpiry = (EXPIRY_DATE - now) / DAYS.toMillis(1);
if (daysSinceLastWarning >= 30) {
showExpiryWarning.postValue(true);
} else if (daysBeforeExpiry <= 3 && daysSinceLastWarning > 0) {
showExpiryWarning.postValue(true); showExpiryWarning.postValue(true);
} else { } else {
long warningLong = warningInt * 1000L; showExpiryWarning.postValue(false);
long now = System.currentTimeMillis();
long daysSinceLastWarning =
(now - warningLong) / DAYS.toMillis(1);
long daysBeforeExpiry =
(EXPIRY_DATE - now) / DAYS.toMillis(1);
if (daysSinceLastWarning >= 30) {
showExpiryWarning.postValue(true);
} else if (daysBeforeExpiry <= 3 &&
daysSinceLastWarning > 0) {
showExpiryWarning.postValue(true);
} else {
showExpiryWarning.postValue(false);
}
} }
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
}); });
} }
@@ -101,15 +93,11 @@ public class NavDrawerViewModel extends DbViewModel {
@UiThread @UiThread
void expiryWarningDismissed() { void expiryWarningDismissed() {
showExpiryWarning.setValue(false); showExpiryWarning.setValue(false);
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = new Settings();
Settings settings = new Settings(); int date = (int) (System.currentTimeMillis() / 1000L);
int date = (int) (System.currentTimeMillis() / 1000L); settings.putInt(EXPIRY_DATE_WARNING, date);
settings.putInt(EXPIRY_DATE_WARNING, date); settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -125,15 +113,12 @@ public class NavDrawerViewModel extends DbViewModel {
return; return;
} }
runOnDbThread(() -> { runOnDbThread(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings = boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true);
settingsManager.getSettings(SETTINGS_NAMESPACE); shouldAskForDozeWhitelisting.postValue(ask);
boolean ask = settings.getBoolean(DOZE_ASK_AGAIN, true); }, e -> {
shouldAskForDozeWhitelisting.postValue(ask); logException(LOG, WARNING, e);
} catch (DbException e) { shouldAskForDozeWhitelisting.postValue(true);
logException(LOG, WARNING, e);
shouldAskForDozeWhitelisting.postValue(true);
}
}); });
} }
@@ -145,30 +130,21 @@ public class NavDrawerViewModel extends DbViewModel {
@UiThread @UiThread
void checkTransportsOnboarding() { void checkTransportsOnboarding() {
if (showTransportsOnboarding.getValue() != null) return; if (showTransportsOnboarding.getValue() != null) return;
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
Settings settings = boolean show =
settingsManager.getSettings(SETTINGS_NAMESPACE); settings.getBoolean(SHOW_TRANSPORTS_ONBOARDING, true);
boolean show = showTransportsOnboarding.postValue(show);
settings.getBoolean(SHOW_TRANSPORTS_ONBOARDING, true);
showTransportsOnboarding.postValue(show);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@UiThread @UiThread
void transportsOnboardingShown() { void transportsOnboardingShown() {
showTransportsOnboarding.setValue(false); showTransportsOnboarding.setValue(false);
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { Settings settings = new Settings();
Settings settings = new Settings(); settings.putBoolean(SHOW_TRANSPORTS_ONBOARDING, false);
settings.putBoolean(SHOW_TRANSPORTS_ONBOARDING, false); settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
} }

View File

@@ -45,12 +45,10 @@ import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE; import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE; import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault @NotNullByDefault
@@ -185,20 +183,16 @@ public class PluginViewModel extends DbViewModel implements EventListener {
} }
private void loadSettings() { private void loadSettings() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { boolean tor = isPluginEnabled(TorConstants.ID,
boolean tor = isPluginEnabled(TorConstants.ID, TorConstants.DEFAULT_PREF_PLUGIN_ENABLE);
TorConstants.DEFAULT_PREF_PLUGIN_ENABLE); torEnabledSetting.postValue(tor);
torEnabledSetting.postValue(tor); boolean wifi = isPluginEnabled(LanTcpConstants.ID,
boolean wifi = isPluginEnabled(LanTcpConstants.ID, LanTcpConstants.DEFAULT_PREF_PLUGIN_ENABLE);
LanTcpConstants.DEFAULT_PREF_PLUGIN_ENABLE); wifiEnabledSetting.postValue(wifi);
wifiEnabledSetting.postValue(wifi); boolean bt = isPluginEnabled(BluetoothConstants.ID,
boolean bt = isPluginEnabled(BluetoothConstants.ID, BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE);
BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE); btEnabledSetting.postValue(bt);
btEnabledSetting.postValue(bt);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -222,14 +216,10 @@ public class PluginViewModel extends DbViewModel implements EventListener {
} }
private void mergeSettings(Settings s, String namespace) { private void mergeSettings(Settings s, String namespace) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); settingsManager.mergeSettings(s, namespace);
settingsManager.mergeSettings(s, namespace); logDuration(LOG, "Merging settings", start);
logDuration(LOG, "Merging settings", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -52,10 +52,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -143,15 +141,11 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
} }
private void loadPrivateGroup(GroupId groupId) { private void loadPrivateGroup(GroupId groupId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { PrivateGroup g = privateGroupManager.getPrivateGroup(groupId);
PrivateGroup g = privateGroupManager.getPrivateGroup(groupId); privateGroup.postValue(g);
privateGroup.postValue(g); Author author = identityManager.getLocalAuthor();
Author author = identityManager.getLocalAuthor(); isCreator.postValue(g.getCreator().equals(author));
isCreator.postValue(g.getCreator().equals(author));
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -190,18 +184,14 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
@Override @Override
public void createAndStoreMessage(String text, public void createAndStoreMessage(String text,
@Nullable MessageId parentId) { @Nullable MessageId parentId) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { LocalAuthor author = identityManager.getLocalAuthor();
LocalAuthor author = identityManager.getLocalAuthor(); MessageId previousMsgId =
MessageId previousMsgId = privateGroupManager.getPreviousMsgId(groupId);
privateGroupManager.getPreviousMsgId(groupId); GroupCount count = privateGroupManager.getGroupCount(groupId);
GroupCount count = privateGroupManager.getGroupCount(groupId); long timestamp = count.getLatestMsgTime();
long timestamp = count.getLatestMsgTime(); timestamp = max(clock.currentTimeMillis(), timestamp + 1);
timestamp = max(clock.currentTimeMillis(), timestamp + 1); createMessage(text, timestamp, parentId, author, previousMsgId);
createMessage(text, timestamp, parentId, author, previousMsgId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@@ -217,55 +207,36 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
} }
private void storePost(GroupMessage msg, String text) { private void storePost(GroupMessage msg, String text) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); GroupMessageHeader header =
GroupMessageHeader header = privateGroupManager.addLocalMessage(msg);
privateGroupManager.addLocalMessage(msg); addItemAsync(buildItem(header, text));
addItemAsync(buildItem(header, text)); logDuration(LOG, "Storing group message", start);
logDuration(LOG, "Storing group message", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
@Override @Override
protected void markItemRead(GroupMessageItem item) { protected void markItemRead(GroupMessageItem item) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { privateGroupManager.setReadFlag(groupId, item.getId(), true));
privateGroupManager.setReadFlag(groupId, item.getId(), true);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
public void loadSharingContacts() { public void loadSharingContacts() {
runOnDbThread(() -> { runOnDbThreadOrLogException(true, txn -> {
try { Collection<GroupMember> members =
Collection<GroupMember> members = privateGroupManager.getMembers(txn, groupId);
privateGroupManager.getMembers(groupId); Collection<ContactId> contactIds = new ArrayList<>();
Collection<ContactId> contactIds = new ArrayList<>(); for (GroupMember m : members) {
for (GroupMember m : members) { if (m.getContactId() != null) contactIds.add(m.getContactId());
if (m.getContactId() != null)
contactIds.add(m.getContactId());
}
sharingController.addAll(contactIds);
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
txn.attach(() -> sharingController.addAll(contactIds));
}); });
} }
void deletePrivateGroup() { void deletePrivateGroup() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() ->
try { privateGroupManager.removePrivateGroup(groupId));
privateGroupManager.removePrivateGroup(groupId);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
} }
LiveData<PrivateGroup> getPrivateGroup() { LiveData<PrivateGroup> getPrivateGroup() {

View File

@@ -2,7 +2,6 @@ package org.briarproject.briar.android.privategroup.list;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
@@ -49,10 +48,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
@@ -200,25 +197,17 @@ class GroupListViewModel extends DbViewModel implements EventListener {
} }
void removeGroup(GroupId g) { void removeGroup(GroupId g) {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { long start = now();
long start = now(); groupManager.removePrivateGroup(g);
groupManager.removePrivateGroup(g); logDuration(LOG, "Removing group", start);
logDuration(LOG, "Removing group", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }
void loadNumInvitations() { void loadNumInvitations() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { int i = groupInvitationManager.getInvitations().size();
int i = groupInvitationManager.getInvitations().size(); numInvitations.postValue(i);
numInvitations.postValue(i);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
}); });
} }

View File

@@ -1,7 +1,6 @@
package org.briarproject.briar.android.sharing; package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -28,7 +27,7 @@ public interface SharingController {
/** /**
* Adds a collection of contacts to be tracked. * Adds a collection of contacts to be tracked.
*/ */
@DatabaseExecutor @UiThread
void addAll(Collection<ContactId> contacts); void addAll(Collection<ContactId> contacts);
/** /**

View File

@@ -2,14 +2,12 @@ package org.briarproject.briar.android.sharing;
import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.connection.ConnectionRegistry;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@@ -26,7 +24,6 @@ public class SharingControllerImpl implements SharingController, EventListener {
private final EventBus eventBus; private final EventBus eventBus;
private final ConnectionRegistry connectionRegistry; private final ConnectionRegistry connectionRegistry;
private final AndroidExecutor executor;
// UI thread // UI thread
private final Set<ContactId> contacts = new HashSet<>(); private final Set<ContactId> contacts = new HashSet<>();
@@ -35,11 +32,9 @@ public class SharingControllerImpl implements SharingController, EventListener {
@Inject @Inject
SharingControllerImpl(EventBus eventBus, SharingControllerImpl(EventBus eventBus,
ConnectionRegistry connectionRegistry, ConnectionRegistry connectionRegistry) {
AndroidExecutor executor) {
this.eventBus = eventBus; this.eventBus = eventBus;
this.connectionRegistry = connectionRegistry; this.connectionRegistry = connectionRegistry;
this.executor = executor;
eventBus.addListener(this); eventBus.addListener(this);
} }
@@ -78,13 +73,11 @@ public class SharingControllerImpl implements SharingController, EventListener {
return online; return online;
} }
@UiThread
@Override @Override
@DatabaseExecutor
public void addAll(Collection<ContactId> c) { public void addAll(Collection<ContactId> c) {
executor.runOnUiThread(() -> { contacts.addAll(c);
contacts.addAll(c); updateLiveData();
updateLiveData();
});
} }
@UiThread @UiThread

View File

@@ -44,10 +44,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@@ -145,16 +143,11 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
} }
private void loadStoredMessageId() { private void loadStoredMessageId() {
runOnDbThread(() -> { runOnDbThreadOrLogException(() -> {
try { storedMessageId.set(messageTracker.loadStoredMessageId(groupId));
storedMessageId if (LOG.isLoggable(INFO)) {
.set(messageTracker.loadStoredMessageId(groupId)); LOG.info("Loaded last top visible message id " +
if (LOG.isLoggable(INFO)) { storedMessageId);
LOG.info("Loaded last top visible message id " +
storedMessageId);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
} }
}); });
} }
@@ -229,13 +222,10 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
} }
void storeMessageId(@Nullable MessageId messageId) { void storeMessageId(@Nullable MessageId messageId) {
if (messageId != null) runOnDbThread(() -> { if (messageId != null) {
try { runOnDbThreadOrLogException(() ->
messageTracker.storeMessageId(groupId, messageId); messageTracker.storeMessageId(groupId, messageId));
} catch (DbException e) { }
logException(LOG, WARNING, e);
}
});
} }
protected abstract void markItemRead(I item); protected abstract void markItemRead(I item);

View File

@@ -2,9 +2,11 @@ package org.briarproject.briar.android.viewmodel;
import android.app.Application; import android.app.Application;
import org.briarproject.bramble.api.ThrowingRunnable;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbCallable; import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -23,6 +25,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.arch.core.util.Function; import androidx.arch.core.util.Function;
import androidx.core.util.Consumer;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -57,14 +60,15 @@ public abstract class DbViewModel extends AndroidViewModel {
} }
/** /**
* Runs the given task on the {@link DatabaseExecutor} * Waits for the DB to open and runs the given task on the
* and waits for the DB to open. * {@link DatabaseExecutor}.
* <p> * <p>
* If you need a list of items to be displayed in a * If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter}, * {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead. * use {@link #loadList(DbCallable, UiConsumer)} instead.
*/ */
protected void runOnDbThread(Runnable task) { protected void runOnDbThread(ThrowingRunnable<Exception> task,
Consumer<Exception> err) {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
@@ -72,10 +76,63 @@ public abstract class DbViewModel extends AndroidViewModel {
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for database"); LOG.warning("Interrupted while waiting for database");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (Exception e) {
err.accept(e);
} }
}); });
} }
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThread(boolean readOnly,
DbRunnable<Exception> task, Consumer<Exception> err) {
dbExecutor.execute(() -> {
try {
lifecycleManager.waitForDatabase();
db.transaction(readOnly, task);
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for database");
Thread.currentThread().interrupt();
} catch (Exception e) {
err.accept(e);
}
});
}
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}. If the task throws a {@link DbException}
* it's caught and logged.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThreadOrLogException(boolean readOnly,
DbRunnable<Exception> task) {
runOnDbThread(readOnly, task, e -> logException(LOG, WARNING, e));
}
/**
* Waits for the DB to open and runs the given task on the
* {@link DatabaseExecutor}. If the task throws a {@link DbException}
* it's caught and logged.
* <p>
* If you need a list of items to be displayed in a
* {@link RecyclerView.Adapter},
* use {@link #loadList(DbCallable, UiConsumer)} instead.
*/
protected void runOnDbThreadOrLogException(
ThrowingRunnable<Exception> task) {
runOnDbThread(task, e -> logException(LOG, WARNING, e));
}
/** /**
* Loads a list of items on the {@link DatabaseExecutor} within a single * Loads a list of items on the {@link DatabaseExecutor} within a single
* {@link Transaction} and publishes it as a {@link LiveResult} * {@link Transaction} and publishes it as a {@link LiveResult}

View File

@@ -129,6 +129,12 @@ public interface PrivateGroupManager {
*/ */
Collection<GroupMember> getMembers(GroupId g) throws DbException; Collection<GroupMember> getMembers(GroupId g) throws DbException;
/**
* Returns all members of the given private group.
*/
Collection<GroupMember> getMembers(Transaction txn, GroupId g)
throws DbException;
/** /**
* Returns true if the given author is a member of the given private group. * Returns true if the given author is a member of the given private group.
*/ */

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.api.sharing;
import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
@@ -45,6 +46,12 @@ public interface SharingManager<S extends Shareable>
*/ */
Collection<Contact> getSharedWith(GroupId g) throws DbException; Collection<Contact> getSharedWith(GroupId g) throws DbException;
/**
* Returns all contacts with whom the given group is shared.
*/
Collection<Contact> getSharedWith(Transaction txn, GroupId g)
throws DbException;
/** /**
* Returns true if the group not already shared and no invitation is open * Returns true if the group not already shared and no invitation is open
*/ */

View File

@@ -407,36 +407,36 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
} }
@Override @Override
public Collection<GroupMember> getMembers(GroupId g) throws DbException { public Collection<GroupMember> getMembers(GroupId g)
Transaction txn = db.startTransaction(true); throws DbException {
try { return db.transactionWithResult(true, txn -> getMembers(txn, g));
Collection<GroupMember> members = new ArrayList<>();
Map<Author, Visibility> authors = getMembers(txn, g);
LocalAuthor la = identityManager.getLocalAuthor(txn);
PrivateGroup privateGroup = getPrivateGroup(txn, g);
for (Entry<Author, Visibility> m : authors.entrySet()) {
Author a = m.getKey();
AuthorInfo authorInfo =
authorManager.getAuthorInfo(txn, a.getId());
Status status = authorInfo.getStatus();
Visibility v = m.getValue();
ContactId c = null;
if (v != INVISIBLE &&
(status == VERIFIED || status == UNVERIFIED)) {
c = contactManager.getContact(txn, a.getId(), la.getId())
.getId();
}
boolean isCreator = privateGroup.getCreator().equals(a);
members.add(new GroupMember(a, authorInfo, isCreator, c, v));
}
db.commitTransaction(txn);
return members;
} finally {
db.endTransaction(txn);
}
} }
private Map<Author, Visibility> getMembers(Transaction txn, GroupId g) @Override
public Collection<GroupMember> getMembers(Transaction txn, GroupId g)
throws DbException {
Collection<GroupMember> members = new ArrayList<>();
Map<Author, Visibility> authors = getMemberAuthors(txn, g);
LocalAuthor la = identityManager.getLocalAuthor(txn);
PrivateGroup privateGroup = getPrivateGroup(txn, g);
for (Entry<Author, Visibility> m : authors.entrySet()) {
Author a = m.getKey();
AuthorInfo authorInfo = authorManager.getAuthorInfo(txn, a.getId());
Status status = authorInfo.getStatus();
Visibility v = m.getValue();
ContactId c = null;
if (v != INVISIBLE &&
(status == VERIFIED || status == UNVERIFIED)) {
c = contactManager.getContact(txn, a.getId(), la.getId())
.getId();
}
boolean isCreator = privateGroup.getCreator().equals(a);
members.add(new GroupMember(a, authorInfo, isCreator, c, v));
}
return members;
}
private Map<Author, Visibility> getMemberAuthors(Transaction txn, GroupId g)
throws DbException { throws DbException {
try { try {
BdfDictionary meta = BdfDictionary meta =
@@ -458,7 +458,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
@Override @Override
public boolean isMember(Transaction txn, GroupId g, Author a) public boolean isMember(Transaction txn, GroupId g, Author a)
throws DbException { throws DbException {
for (Author member : getMembers(txn, g).keySet()) { for (Author member : getMemberAuthors(txn, g).keySet()) {
if (member.equals(a)) return true; if (member.equals(a)) return true;
} }
return false; return false;

View File

@@ -426,17 +426,17 @@ abstract class SharingManagerImpl<S extends Shareable>
@Override @Override
public Collection<Contact> getSharedWith(GroupId g) throws DbException { public Collection<Contact> getSharedWith(GroupId g) throws DbException {
return db.transactionWithResult(true, txn -> getSharedWith(txn, g));
}
@Override
public Collection<Contact> getSharedWith(Transaction txn, GroupId g)
throws DbException {
// TODO report also pending invitations // TODO report also pending invitations
Collection<Contact> contacts = new ArrayList<>(); Collection<Contact> contacts = new ArrayList<>();
Transaction txn = db.startTransaction(true); for (Contact c : db.getContacts(txn)) {
try { if (db.getGroupVisibility(txn, c.getId(), g) == SHARED)
for (Contact c : db.getContacts(txn)) { contacts.add(c);
if (db.getGroupVisibility(txn, c.getId(), g) == SHARED)
contacts.add(c);
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
} }
return contacts; return contacts;
} }

View File

@@ -20,10 +20,10 @@ import org.junit.Test;
import java.util.Collection; import java.util.Collection;
import static org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.briar.api.identity.AuthorInfo.Status.VERIFIED;
import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE; import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT; import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_CONTACT;
import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_US; import static org.briarproject.briar.api.privategroup.Visibility.REVEALED_BY_US;