From 50a70f7649b84969adac52e81772bdeb89e5b456 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 12 Oct 2016 16:55:00 +0100 Subject: [PATCH 1/5] Use start/stop lifecycle callbacks rather than pause/resume. Also fixed a couple of bugs. --- .../briarproject/android/BaseActivity.java | 13 +- .../briarproject/android/BriarActivity.java | 11 +- .../android/NavDrawerActivity.java | 4 +- .../android/blogs/BaseControllerImpl.java | 42 +++--- .../android/blogs/BlogControllerImpl.java | 35 +++-- .../android/blogs/BlogFragment.java | 21 ++- .../android/blogs/FeedController.java | 3 +- .../android/blogs/FeedControllerImpl.java | 32 +++-- .../android/blogs/FeedFragment.java | 69 ++++++---- .../android/blogs/RssFeedManageActivity.java | 17 ++- .../android/blogs/WriteBlogPostActivity.java | 12 +- .../contact/BaseContactListAdapter.java | 12 -- .../android/contact/ContactListFragment.java | 51 +++---- .../android/contact/ConversationActivity.java | 128 ++++++------------ .../ActivityLifecycleController.java | 4 +- .../controller/BriarControllerImpl.java | 22 ++- .../controller/NavDrawerControllerImpl.java | 4 +- .../android/forum/ForumActivity.java | 37 ++--- .../android/forum/ForumControllerImpl.java | 15 +- .../android/forum/ForumListFragment.java | 20 ++- .../android/fragment/BaseEventFragment.java | 8 +- .../android/fragment/BaseFragment.java | 1 + .../android/fragment/SettingsFragment.java | 8 +- .../introduction/ContactChooserAdapter.java | 10 +- .../introduction/ContactChooserFragment.java | 29 ++-- .../introduction/IntroductionActivity.java | 11 +- .../invitation/AddContactActivity.java | 17 ++- .../keyagreement/KeyAgreementActivity.java | 18 ++- .../keyagreement/ShowQrCodeFragment.java | 11 +- .../panic/PanicPreferencesFragment.java | 8 +- .../conversation/GroupControllerImpl.java | 13 +- .../android/privategroup/list/GroupItem.java | 31 ++--- .../privategroup/list/GroupListAdapter.java | 4 +- .../list/GroupListController.java | 1 + .../list/GroupListControllerImpl.java | 87 +++++++----- .../privategroup/list/GroupListFragment.java | 11 +- .../privategroup/list/GroupViewHolder.java | 2 +- .../android/report/DevReportActivity.java | 4 +- .../sharing/ContactSelectorFragment.java | 33 +++-- .../android/sharing/InvitationsActivity.java | 15 +- .../sharing/InvitationsBlogActivity.java | 14 +- .../sharing/InvitationsForumActivity.java | 14 +- .../sharing/SharingStatusActivity.java | 40 +++--- .../android/threaded/ThreadListActivity.java | 22 ++- .../threaded/ThreadListControllerImpl.java | 39 +++--- .../android/util/BriarAdapter.java | 7 + .../api/crypto/CryptoExecutor.java | 22 ++- .../briarproject/api/db/DatabaseExecutor.java | 20 +-- .../event/PrivateMessageReceivedEvent.java | 9 +- .../api/lifecycle/IoExecutor.java | 24 ++-- .../messaging/MessagingManagerImpl.java | 16 ++- 51 files changed, 563 insertions(+), 538 deletions(-) diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java index fa3671b50..a144adb9e 100644 --- a/briar-android/src/org/briarproject/android/BaseActivity.java +++ b/briar-android/src/org/briarproject/android/BaseActivity.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.List; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; -import static android.view.inputmethod.InputMethodManager.SHOW_FORCED; import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS; @@ -62,18 +61,18 @@ public abstract class BaseActivity extends AppCompatActivity } @Override - protected void onResume() { - super.onResume(); + protected void onStart() { + super.onStart(); for (ActivityLifecycleController alc : lifecycleControllers) { - alc.onActivityResume(); + alc.onActivityStart(); } } @Override - protected void onPause() { - super.onPause(); + protected void onStop() { + super.onStop(); for (ActivityLifecycleController alc : lifecycleControllers) { - alc.onActivityPause(); + alc.onActivityStop(); } } diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java index 4c01808af..c0bda36a8 100644 --- a/briar-android/src/org/briarproject/android/BriarActivity.java +++ b/briar-android/src/org/briarproject/android/BriarActivity.java @@ -34,10 +34,11 @@ public abstract class BriarActivity extends BaseActivity { Logger.getLogger(BriarActivity.class.getName()); @Inject - protected BriarController briarController; - // TODO remove this when the deprecated method runOnDbThread is removed + BriarController briarController; + + @Deprecated @Inject - protected DbController dbController; + DbController dbController; @Override protected void onActivityResult(int request, int result, Intent data) { @@ -49,8 +50,8 @@ public abstract class BriarActivity extends BaseActivity { } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); if (!briarController.hasEncryptionKey() && !isFinishing()) { Intent i = new Intent(this, PasswordActivity.class); i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP); diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java index 751700559..5d69216a7 100644 --- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java +++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java @@ -141,8 +141,8 @@ public class NavDrawerActivity extends BriarFragmentActivity implements } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); updateTransports(); } diff --git a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java index 0015bc111..7ff91c18b 100644 --- a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java @@ -12,8 +12,6 @@ import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DbException; -import org.briarproject.api.event.BlogPostAddedEvent; -import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.identity.IdentityManager; @@ -47,7 +45,7 @@ abstract class BaseControllerImpl extends DbControllerImpl private final Map headerCache = new ConcurrentHashMap<>(); - protected volatile OnBlogPostAddedListener listener; + private volatile OnBlogPostAddedListener listener; BaseControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, EventBus eventBus, @@ -63,9 +61,7 @@ abstract class BaseControllerImpl extends DbControllerImpl @Override @CallSuper public void onStart() { - if (listener == null) - throw new IllegalStateException( - "OnBlogPostAddedListener needs to be attached"); + if (listener == null) throw new IllegalStateException(); eventBus.addListener(this); } @@ -75,26 +71,30 @@ abstract class BaseControllerImpl extends DbControllerImpl eventBus.removeListener(this); } - @Override - @CallSuper - public void eventOccurred(Event e) { - if (e instanceof BlogPostAddedEvent) { - final BlogPostAddedEvent b = (BlogPostAddedEvent) e; - LOG.info("New blog post added"); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onBlogPostAdded(b.getHeader(), b.isLocal()); - } - }); - } - } - @Override public void setOnBlogPostAddedListener(OnBlogPostAddedListener listener) { this.listener = listener; } + void onBlogPostAdded(final BlogPostHeader h, final boolean local) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onBlogPostAdded(h, local); + } + }); + } + + void onBlogRemoved() { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onBlogRemoved(); + } + }); + } + + @Override public void loadBlogPosts(final GroupId groupId, final ResultExceptionHandler, DbException> handler) { diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java index 5394821f8..64cee65a5 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java @@ -26,6 +26,7 @@ import java.util.logging.Logger; import javax.inject.Inject; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; public class BlogControllerImpl extends BaseControllerImpl @@ -50,15 +51,15 @@ public class BlogControllerImpl extends BaseControllerImpl } @Override - public void onActivityResume() { - super.onStart(); // TODO: Should be called when activity starts. #609 + public void onActivityStart() { + super.onStart(); notificationManager.blockNotification(groupId); notificationManager.clearBlogPostNotification(groupId); } @Override - public void onActivityPause() { - super.onStop(); // TODO: Should be called when activity stops. #609 + public void onActivityStop() { + super.onStop(); notificationManager.unblockNotification(groupId); } @@ -75,20 +76,16 @@ public class BlogControllerImpl extends BaseControllerImpl public void eventOccurred(Event e) { if (groupId == null) throw new IllegalStateException(); if (e instanceof BlogPostAddedEvent) { - BlogPostAddedEvent s = (BlogPostAddedEvent) e; - if (s.getGroupId().equals(groupId)) { - super.eventOccurred(e); + BlogPostAddedEvent b = (BlogPostAddedEvent) e; + if (b.getGroupId().equals(groupId)) { + LOG.info("Blog post added"); + onBlogPostAdded(b.getHeader(), b.isLocal()); } } else if (e instanceof GroupRemovedEvent) { - GroupRemovedEvent s = (GroupRemovedEvent) e; - if (s.getGroup().getId().equals(groupId)) { + GroupRemovedEvent g = (GroupRemovedEvent) e; + if (g.getGroup().getId().equals(groupId)) { LOG.info("Blog removed"); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onBlogRemoved(); - } - }); + onBlogRemoved(); } } } @@ -115,11 +112,15 @@ public class BlogControllerImpl extends BaseControllerImpl @Override public void run() { try { + long now = System.currentTimeMillis(); LocalAuthor a = identityManager.getLocalAuthor(); Blog b = blogManager.getBlog(groupId); boolean ours = a.getId().equals(b.getAuthor().getId()); boolean removable = blogManager.canBeRemoved(groupId); BlogItem blog = new BlogItem(b, ours, removable); + long duration = System.currentTimeMillis() - now; + if (LOG.isLoggable(INFO)) + LOG.info("Loading blog took " + duration + " ms"); handler.onResult(blog); } catch (DbException e) { if (LOG.isLoggable(WARNING)) @@ -138,8 +139,12 @@ public class BlogControllerImpl extends BaseControllerImpl @Override public void run() { try { + long now = System.currentTimeMillis(); Blog b = blogManager.getBlog(groupId); blogManager.removeBlog(b); + long duration = System.currentTimeMillis() - now; + if (LOG.isLoggable(INFO)) + LOG.info("Removing blog took " + duration + " ms"); handler.onResult(null); } catch (DbException e) { if (LOG.isLoggable(WARNING)) diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index 25d266c31..eb6552091 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -123,18 +123,13 @@ public class BlogFragment extends BaseFragment implements public void onStart() { super.onStart(); loadBlog(); - } - - @Override - public void onResume() { - super.onResume(); loadBlogPosts(false); list.startPeriodicUpdate(); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); list.stopPeriodicUpdate(); } @@ -215,9 +210,11 @@ public class BlogFragment extends BaseFragment implements adapter.add(post); if (local) { list.scrollToPosition(0); - displaySnackbar(R.string.blogs_blog_post_created, false); + displaySnackbar(R.string.blogs_blog_post_created, + false); } else { - displaySnackbar(R.string.blogs_blog_post_received, true); + displaySnackbar(R.string.blogs_blog_post_received, + true); } } @@ -236,11 +233,11 @@ public class BlogFragment extends BaseFragment implements listener) { @Override public void onResultUi(Collection posts) { - if (posts.size() > 0) { + if (posts.isEmpty()) { + list.showData(); + } else { adapter.addAll(posts); if (reload) list.scrollToPosition(0); - } else { - list.showData(); } } diff --git a/briar-android/src/org/briarproject/android/blogs/FeedController.java b/briar-android/src/org/briarproject/android/blogs/FeedController.java index e2934f49f..90015b066 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedController.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedController.java @@ -1,7 +1,6 @@ package org.briarproject.android.blogs; import org.briarproject.android.controller.handler.ResultExceptionHandler; -import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.api.blogs.Blog; import org.briarproject.api.db.DbException; @@ -12,6 +11,6 @@ public interface FeedController extends BaseController { void loadBlogPosts( ResultExceptionHandler, DbException> handler); - void loadPersonalBlog(ResultHandler resultHandler); + void loadPersonalBlog(ResultExceptionHandler handler); } diff --git a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java index 0d85144d8..faf626b54 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java @@ -2,14 +2,16 @@ package org.briarproject.android.blogs; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.controller.handler.ResultExceptionHandler; -import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.api.blogs.Blog; import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DbException; import org.briarproject.api.db.NoSuchGroupException; import org.briarproject.api.db.NoSuchMessageException; +import org.briarproject.api.event.BlogPostAddedEvent; +import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; +import org.briarproject.api.event.GroupRemovedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.lifecycle.LifecycleManager; @@ -52,15 +54,28 @@ public class FeedControllerImpl extends BaseControllerImpl notificationManager.unblockAllBlogPostNotifications(); } + @Override + public void eventOccurred(Event e) { + if (e instanceof BlogPostAddedEvent) { + BlogPostAddedEvent b = (BlogPostAddedEvent) e; + LOG.info("Blog post added"); + onBlogPostAdded(b.getHeader(), b.isLocal()); + } else if (e instanceof GroupRemovedEvent) { + GroupRemovedEvent g = (GroupRemovedEvent) e; + if (g.getGroup().getClientId().equals(blogManager.getClientId())) { + LOG.info("Blog removed"); + onBlogRemoved(); + } + } + } + @Override public void loadBlogPosts( final ResultExceptionHandler, DbException> handler) { - LOG.info("Loading all blog posts..."); runOnDbThread(new Runnable() { @Override public void run() { try { - // load blog posts long now = System.currentTimeMillis(); Collection posts = new ArrayList<>(); for (Blog b : blogManager.getBlogs()) { @@ -85,24 +100,23 @@ public class FeedControllerImpl extends BaseControllerImpl } @Override - public void loadPersonalBlog(final ResultHandler resultHandler) { - LOG.info("Loading personal blog..."); + public void loadPersonalBlog( + final ResultExceptionHandler handler) { runOnDbThread(new Runnable() { @Override public void run() { try { - // load blog posts long now = System.currentTimeMillis(); Author a = identityManager.getLocalAuthor(); Blog b = blogManager.getPersonalBlog(a); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) - LOG.info("Loading pers. blog took " + duration + " ms"); - resultHandler.onResult(b); + LOG.info("Loading blog took " + duration + " ms"); + handler.onResult(b); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - resultHandler.onResult(null); + handler.onException(e); } } }); diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index d07a800d5..6f960d3c1 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -20,7 +20,6 @@ import org.briarproject.android.ActivityComponent; import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener; import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener; import org.briarproject.android.controller.handler.UiResultExceptionHandler; -import org.briarproject.android.controller.handler.UiResultHandler; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.view.BriarRecyclerView; import org.briarproject.api.blogs.Blog; @@ -99,40 +98,56 @@ public class FeedFragment extends BaseFragment implements public void onStart() { super.onStart(); feedController.onStart(); - feedController.loadPersonalBlog( - new UiResultHandler(listener) { - @Override - public void onResultUi(Blog b) { - personalBlog = b; - } - }); - feedController.loadBlogPosts( - new UiResultExceptionHandler, DbException>( - listener) { - @Override - public void onResultUi(Collection posts) { - if (posts.isEmpty()) { - list.showData(); - } else { - adapter.addAll(posts); - } - } - @Override - public void onExceptionUi(DbException exception) { - // TODO - } - }); - list.startPeriodicUpdate(); + loadPersonalBlog(); + loadBlogPosts(false); } @Override public void onStop() { super.onStop(); feedController.onStop(); + adapter.clear(); + list.showProgressBar(); list.stopPeriodicUpdate(); // TODO save list position in database/preferences? } + private void loadPersonalBlog() { + feedController.loadPersonalBlog( + new UiResultExceptionHandler(listener) { + @Override + public void onResultUi(Blog b) { + personalBlog = b; + } + + @Override + public void onExceptionUi(DbException exception) { + // TODO: Decide how to handle errors in the UI + finish(); + } + }); + } + + private void loadBlogPosts(final boolean clear) { + feedController.loadBlogPosts( + new UiResultExceptionHandler, DbException>( + listener) { + @Override + public void onResultUi(Collection posts) { + if (clear) adapter.setItems(posts); + else adapter.addAll(posts); + if (posts.isEmpty()) list.showData(); + } + + @Override + public void onExceptionUi(DbException e) { + // TODO: Decide how to handle errors in the UI + finish(); + } + }); + list.startPeriodicUpdate(); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.blogs_feed_actions, menu); @@ -185,9 +200,11 @@ public class FeedFragment extends BaseFragment implements showSnackBar(R.string.blogs_blog_post_received); } } + @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI + finish(); } } ); @@ -234,6 +251,6 @@ public class FeedFragment extends BaseFragment implements @Override public void onBlogRemoved() { - finish(); + loadBlogPosts(true); } } diff --git a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java index 2fe3ad30c..0eb6df792 100644 --- a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java @@ -37,9 +37,7 @@ public class RssFeedManageActivity extends BriarActivity private BriarRecyclerView list; private RssFeedAdapter adapter; - - // Fields that are accessed from background threads must be volatile - private volatile GroupId groupId = null; + private GroupId groupId; @Inject @SuppressWarnings("WeakerAccess") @@ -65,11 +63,18 @@ public class RssFeedManageActivity extends BriarActivity } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); loadFeeds(); } + @Override + public void onStop() { + super.onStop(); + adapter.clear(); + list.showProgressBar(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); @@ -139,7 +144,7 @@ public class RssFeedManageActivity extends BriarActivity runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (feeds.size() == 0) list.showData(); + if (feeds.isEmpty()) list.showData(); else adapter.addAll(feeds); } }); diff --git a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java index 70d326ca4..014f0d1f4 100644 --- a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java @@ -94,15 +94,15 @@ public class WriteBlogPostActivity extends BriarActivity } @Override - public void onPause() { - super.onPause(); - notificationManager.unblockNotification(groupId); + public void onStart() { + super.onStart(); + notificationManager.blockNotification(groupId); } @Override - public void onResume() { - super.onResume(); - notificationManager.blockNotification(groupId); + public void onStop() { + super.onStop(); + notificationManager.unblockNotification(groupId); } @Override diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java index aa48714f7..cd01ad1a4 100644 --- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java +++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java @@ -13,7 +13,6 @@ import org.briarproject.R; import org.briarproject.android.util.BriarAdapter; import org.briarproject.api.contact.ContactId; import org.briarproject.api.identity.Author; -import org.briarproject.api.sync.GroupId; import org.briarproject.util.StringUtils; import im.delight.android.identicons.IdenticonDrawable; @@ -90,17 +89,6 @@ public abstract class BaseContactListAdapter items = new ArrayList<>(); + List items = new ArrayList<>(size); for (PrivateMessageHeader h : headers) { ConversationMessageItem item = ConversationItem.from(h); byte[] body = bodyCache.get(h.getId()); @@ -392,28 +388,26 @@ public class ConversationActivity extends BriarActivity else item.setBody(body); items.add(item); } - for (IntroductionMessage m : introductions) { - ConversationItem item; - if (m instanceof IntroductionRequest) { - item = ConversationItem - .from((IntroductionRequest) m); + for (IntroductionMessage im : introductions) { + if (im instanceof IntroductionRequest) { + IntroductionRequest ir = (IntroductionRequest) im; + items.add(ConversationItem.from(ir)); } else { - item = ConversationItem - .from(ConversationActivity.this, - contactName, - (IntroductionResponse) m); - } - items.add(item); - } - for (InvitationMessage i : invitations) { - if (i instanceof InvitationRequest) { - InvitationRequest r = (InvitationRequest) i; - items.add(ConversationItem.from(r)); - } else if (i instanceof InvitationResponse) { - InvitationResponse r = (InvitationResponse) i; + IntroductionResponse ir = (IntroductionResponse) im; items.add(ConversationItem .from(ConversationActivity.this, - contactName, r)); + contactName, ir)); + } + } + for (InvitationMessage im : invitations) { + if (im instanceof InvitationRequest) { + InvitationRequest ir = (InvitationRequest) im; + items.add(ConversationItem.from(ir)); + } else if (im instanceof InvitationResponse) { + InvitationResponse ir = (InvitationResponse) im; + items.add(ConversationItem + .from(ConversationActivity.this, + contactName, ir)); } } adapter.addAll(items); @@ -435,8 +429,6 @@ public class ConversationActivity extends BriarActivity if (LOG.isLoggable(INFO)) LOG.info("Loading body took " + duration + " ms"); displayMessageBody(m, body); - } catch (NoSuchMessageException e) { - // The item will be removed when we get the event } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -496,9 +488,10 @@ public class ConversationActivity extends BriarActivity public void run() { try { long now = System.currentTimeMillis(); - for (Map.Entry e : unread.entrySet()) - messagingManager - .setReadFlag(e.getValue(), e.getKey(), true); + for (Map.Entry e : unread.entrySet()) { + messagingManager.setReadFlag(e.getValue(), e.getKey(), + true); + } long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Marking read took " + duration + " ms"); @@ -525,7 +518,6 @@ public class ConversationActivity extends BriarActivity PrivateMessageHeader h = p.getMessageHeader(); addConversationItem(ConversationItem.from(h)); loadMessageBody(h.getId()); - markMessageReadIfNew(h); } } else if (e instanceof MessagesSentEvent) { MessagesSentEvent m = (MessagesSentEvent) e; @@ -543,15 +535,13 @@ public class ConversationActivity extends BriarActivity ContactConnectedEvent c = (ContactConnectedEvent) e; if (c.getContactId().equals(contactId)) { LOG.info("Contact connected"); - connected = true; - displayContactDetails(); + displayContactDetails(true); } } else if (e instanceof ContactDisconnectedEvent) { ContactDisconnectedEvent c = (ContactDisconnectedEvent) e; if (c.getContactId().equals(contactId)) { LOG.info("Contact disconnected"); - connected = false; - displayContactDetails(); + displayContactDetails(false); } } else if (e instanceof IntroductionRequestReceivedEvent) { IntroductionRequestReceivedEvent event = @@ -561,7 +551,6 @@ public class ConversationActivity extends BriarActivity IntroductionRequest ir = event.getIntroductionRequest(); ConversationItem item = new ConversationIntroductionInItem(ir); addConversationItem(item); - markMessageReadIfNew(ir); } } else if (e instanceof IntroductionResponseReceivedEvent) { IntroductionResponseReceivedEvent event = @@ -572,7 +561,6 @@ public class ConversationActivity extends BriarActivity ConversationItem item = ConversationItem.from(this, contactName, ir); addConversationItem(item); - markMessageReadIfNew(ir); } } else if (e instanceof InvitationRequestReceivedEvent) { InvitationRequestReceivedEvent event = @@ -582,7 +570,6 @@ public class ConversationActivity extends BriarActivity InvitationRequest ir = event.getRequest(); ConversationItem item = ConversationItem.from(ir); addConversationItem(item); - markMessageReadIfNew(ir); } } else if (e instanceof InvitationResponseReceivedEvent) { InvitationResponseReceivedEvent event = @@ -593,46 +580,10 @@ public class ConversationActivity extends BriarActivity ConversationItem item = ConversationItem.from(this, contactName, ir); addConversationItem(item); - markMessageReadIfNew(ir); } } } - private void markMessageReadIfNew(final BaseMessageHeader h) { - runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - ConversationItem item = adapter.getLastItem(); - if (item != null) { - // Mark the message read if it's the newest message - long lastMsgTime = item.getTime(); - long newMsgTime = h.getTimestamp(); - if (newMsgTime > lastMsgTime) - markNewMessageRead(h.getGroupId(), h.getId()); - else loadMessages(); - } else { - // mark the message as read as well if it is the first one - markNewMessageRead(h.getGroupId(), h.getId()); - } - } - }); - } - - private void markNewMessageRead(final GroupId g, final MessageId m) { - runOnDbThread(new Runnable() { - @Override - public void run() { - try { - messagingManager.setReadFlag(g, m, true); - loadMessages(); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - }); - } - private void markMessages(final Collection messageIds, final boolean sent, final boolean seen) { runOnUiThreadUnlessDestroyed(new Runnable() { @@ -654,7 +605,6 @@ public class ConversationActivity extends BriarActivity @Override public void onSendClick(String text) { - markMessagesRead(); if (text.equals("")) return; long timestamp = System.currentTimeMillis(); timestamp = Math.max(timestamp, getMinTimestampForNewMessage()); diff --git a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java index 303f9b89b..96d0cf4f0 100644 --- a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java +++ b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java @@ -6,9 +6,9 @@ public interface ActivityLifecycleController { void onActivityCreate(Activity activity); - void onActivityResume(); + void onActivityStart(); - void onActivityPause(); + void onActivityStop(); void onActivityDestroy(); } diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java index 459730ebd..f49d6485f 100644 --- a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java +++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java @@ -19,18 +19,18 @@ public class BriarControllerImpl implements BriarController { private static final Logger LOG = Logger.getLogger(BriarControllerImpl.class.getName()); - @Inject - BriarServiceConnection serviceConnection; - @Inject - DatabaseConfig databaseConfig; - @Inject - Activity activity; + private final BriarServiceConnection serviceConnection; + private final DatabaseConfig databaseConfig; + private final Activity activity; private boolean bound = false; @Inject - public BriarControllerImpl() { - + BriarControllerImpl(BriarServiceConnection serviceConnection, + DatabaseConfig databaseConfig, Activity activity) { + this.serviceConnection = serviceConnection; + this.databaseConfig = databaseConfig; + this.activity = activity; } @Override @@ -40,13 +40,11 @@ public class BriarControllerImpl implements BriarController { } @Override - @CallSuper - public void onActivityResume() { + public void onActivityStart() { } @Override - @CallSuper - public void onActivityPause() { + public void onActivityStop() { } @Override diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java index 060f77933..55d5d267f 100644 --- a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java +++ b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java @@ -57,12 +57,12 @@ public class NavDrawerControllerImpl extends DbControllerImpl } @Override - public void onActivityResume() { + public void onActivityStart() { eventBus.addListener(this); } @Override - public void onActivityPause() { + public void onActivityStop() { eventBus.removeListener(this); } diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 81b41f99f..03ebdf438 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -1,6 +1,7 @@ package org.briarproject.android.forum; import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.os.Bundle; import android.support.annotation.LayoutRes; @@ -98,9 +99,8 @@ public class ForumActivity extends @Override public boolean onOptionsItemSelected(final MenuItem item) { - ActivityOptionsCompat options = - makeCustomAnimation(this, android.R.anim.slide_in_left, - android.R.anim.slide_out_right); + ActivityOptionsCompat options = makeCustomAnimation(this, + android.R.anim.slide_in_left, android.R.anim.slide_out_right); // Handle presses on the action bar items switch (item.getItemId()) { case R.id.action_forum_compose_post: @@ -110,9 +110,8 @@ public class ForumActivity extends Intent i2 = new Intent(this, ShareForumActivity.class); i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP); i2.putExtra(GROUP_ID, groupId.getBytes()); - ActivityCompat - .startActivityForResult(this, i2, REQUEST_FORUM_SHARED, - options.toBundle()); + ActivityCompat.startActivityForResult(this, i2, + REQUEST_FORUM_SHARED, options.toBundle()); return true; case R.id.action_forum_sharing_status: Intent i3 = new Intent(this, SharingStatusForumActivity.class); @@ -146,17 +145,14 @@ public class ForumActivity extends } private void showUnsubscribeDialog() { - DialogInterface.OnClickListener okListener = - new DialogInterface.OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, - int which) { - deleteNamedGroup(); - } - }; - AlertDialog.Builder builder = - new AlertDialog.Builder(ForumActivity.this, - R.style.BriarDialogTheme); + OnClickListener okListener = new OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, int which) { + deleteNamedGroup(); + } + }; + AlertDialog.Builder builder = new AlertDialog.Builder( + ForumActivity.this, R.style.BriarDialogTheme); builder.setTitle(getString(R.string.dialog_title_leave_forum)); builder.setMessage(getString(R.string.dialog_message_leave_forum)); builder.setNegativeButton(R.string.dialog_button_leave, okListener); @@ -171,14 +167,11 @@ public class ForumActivity extends @Override public void onResultUi(Void v) { Toast.makeText(ForumActivity.this, - R.string.forum_left_toast, - LENGTH_SHORT) - .show(); + R.string.forum_left_toast, LENGTH_SHORT).show(); } @Override - public void onExceptionUi( - DbException exception) { + public void onExceptionUi(DbException exception) { // TODO proper error handling finish(); } diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java index fa62f1b29..a0b89b0ed 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java +++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java @@ -28,8 +28,8 @@ import java.util.logging.Logger; import javax.inject.Inject; -public class ForumControllerImpl - extends ThreadListControllerImpl +public class ForumControllerImpl extends + ThreadListControllerImpl implements ForumController { private static final Logger LOG = @@ -49,8 +49,8 @@ public class ForumControllerImpl } @Override - public void onActivityResume() { - super.onActivityResume(); + public void onActivityStart() { + super.onActivityStart(); notificationManager.clearForumPostNotification(getGroupId()); } @@ -59,7 +59,7 @@ public class ForumControllerImpl super.eventOccurred(e); if (e instanceof ForumPostReceivedEvent) { - final ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; + ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; if (pe.getGroupId().equals(getGroupId())) { LOG.info("Forum post received, adding..."); final ForumPostHeader fph = pe.getForumPostHeader(); @@ -102,9 +102,8 @@ public class ForumControllerImpl @Override protected ForumPost createLocalMessage(String body, long timestamp, @Nullable MessageId parentId, LocalAuthor author) { - return forumManager - .createLocalPost(getGroupId(), body, timestamp, parentId, - author); + return forumManager.createLocalPost(getGroupId(), body, timestamp, + parentId, author); } @Override diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index 1ebba8c1c..0edb1a075 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -111,9 +111,8 @@ public class ForumListFragment extends BaseEventFragment implements } @Override - public void onResume() { - super.onResume(); - + public void onStart() { + super.onStart(); notificationManager.blockAllForumPostNotifications(); notificationManager.clearAllForumPostNotifications(); loadForums(); @@ -122,9 +121,8 @@ public class ForumListFragment extends BaseEventFragment implements } @Override - public void onPause() { - super.onPause(); - + public void onStop() { + super.onStop(); notificationManager.unblockAllForumPostNotifications(); adapter.clear(); list.showProgressBar(); @@ -156,7 +154,6 @@ public class ForumListFragment extends BaseEventFragment implements @Override public void run() { try { - // load forums long now = System.currentTimeMillis(); Collection forums = new ArrayList<>(); for (Forum f : forumManager.getForums()) { @@ -168,10 +165,10 @@ public class ForumListFragment extends BaseEventFragment implements // Continue } } - displayForums(forums); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Full load took " + duration + " ms"); + displayForums(forums); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -184,8 +181,8 @@ public class ForumListFragment extends BaseEventFragment implements listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (forums.size() > 0) adapter.addAll(forums); - else list.showData(); + if (forums.isEmpty()) list.showData(); + else adapter.addAll(forums); } }); } @@ -245,9 +242,10 @@ public class ForumListFragment extends BaseEventFragment implements } } else if (e instanceof ForumPostReceivedEvent) { ForumPostReceivedEvent f = (ForumPostReceivedEvent) e; - LOG.info("Forum post added, updating..."); + LOG.info("Forum post added, updating item"); updateItem(f.getGroupId(), f.getForumPostHeader()); } else if (e instanceof ForumInvitationReceivedEvent) { + LOG.info("Forum invitation received, reloading available forums"); loadAvailableForums(); } } diff --git a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java index 69ceab43a..cf7884053 100644 --- a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java @@ -12,14 +12,14 @@ public abstract class BaseEventFragment extends BaseFragment implements protected volatile EventBus eventBus; @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); eventBus.addListener(this); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); eventBus.removeListener(this); } } diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java index d671bf245..2cb6b13e6 100644 --- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java @@ -44,6 +44,7 @@ public abstract class BaseFragment extends Fragment public interface BaseFragmentListener extends DestroyableContext { + @Deprecated void runOnDbThread(Runnable runnable); @UiThread diff --git a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java index 15c718b67..a3d655126 100644 --- a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java +++ b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java @@ -155,14 +155,14 @@ public class SettingsFragment extends PreferenceFragmentCompat } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); eventBus.addListener(this); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); eventBus.removeListener(this); } diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java index 059ab8cd1..e291302b8 100644 --- a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java +++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java @@ -1,19 +1,19 @@ package org.briarproject.android.introduction; import android.content.Context; +import android.support.annotation.UiThread; import android.view.View; import org.briarproject.android.contact.ContactListAdapter; import org.briarproject.android.contact.ContactListItem; import org.briarproject.api.identity.AuthorId; -public class ContactChooserAdapter extends ContactListAdapter { +@UiThread +class ContactChooserAdapter extends ContactListAdapter { private AuthorId localAuthorId; - public ContactChooserAdapter(Context context, - OnItemClickListener listener) { - + ContactChooserAdapter(Context context, OnItemClickListener listener) { super(context, listener); } @@ -46,7 +46,7 @@ public class ContactChooserAdapter extends ContactListAdapter { * * @param authorId The ID of the local Author */ - public void setLocalAuthor(AuthorId authorId) { + void setLocalAuthor(AuthorId authorId) { localAuthorId = authorId; notifyDataSetChanged(); } diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java index b26d3a8dc..888cc61e7 100644 --- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java +++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java @@ -45,18 +45,18 @@ public class ContactChooserFragment extends BaseFragment { private IntroductionActivity introductionActivity; private BriarRecyclerView list; private ContactChooserAdapter adapter; - private int contactId; + private ContactId contactId; // Fields that are accessed from background threads must be volatile - protected volatile Contact c1; + volatile Contact c1; @Inject - protected volatile ContactManager contactManager; + volatile ContactManager contactManager; @Inject - protected volatile IdentityManager identityManager; + volatile IdentityManager identityManager; @Inject - protected volatile ConversationManager conversationManager; + volatile ConversationManager conversationManager; @Inject - protected volatile ConnectionRegistry connectionRegistry; + volatile ConnectionRegistry connectionRegistry; public static ContactChooserFragment newInstance() { @@ -87,9 +87,7 @@ public class ContactChooserFragment extends BaseFragment { new ContactListAdapter.OnItemClickListener() { @Override public void onItemClick(View view, ContactListItem item) { - if (c1 == null) { - throw new RuntimeException("c1 not accountExists"); - } + if (c1 == null) throw new IllegalStateException(); Contact c2 = item.getContact(); if (!c1.getLocalAuthorId() .equals(c2.getLocalAuthorId())) { @@ -113,15 +111,14 @@ public class ContactChooserFragment extends BaseFragment { } @Override - public void onResume() { - super.onResume(); - + public void onStart() { + super.onStart(); loadContacts(); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); adapter.clear(); list.showProgressBar(); } @@ -145,7 +142,7 @@ public class ContactChooserFragment extends BaseFragment { AuthorId localAuthorId = identityManager.getLocalAuthor().getId(); for (Contact c : contactManager.getActiveContacts()) { - if (c.getId().getInt() == contactId) { + if (c.getId().equals(contactId)) { c1 = c; } else { ContactId id = c.getId(); @@ -176,7 +173,7 @@ public class ContactChooserFragment extends BaseFragment { @Override public void run() { adapter.setLocalAuthor(localAuthorId); - if (contacts.size() == 0) list.showData(); + if (contacts.isEmpty()) list.showData(); else adapter.addAll(contacts); } }); diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java index 8c4e64652..aeada3f1d 100644 --- a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java +++ b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java @@ -14,6 +14,7 @@ import org.briarproject.android.ActivityComponent; import org.briarproject.android.BriarActivity; import org.briarproject.android.fragment.BaseFragment; import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; // TODO extend the BriarFragmentActivity ? public class IntroductionActivity extends BriarActivity implements @@ -21,16 +22,16 @@ public class IntroductionActivity extends BriarActivity implements public static final String CONTACT_ID = "briar.CONTACT_ID"; - private int contactId; + private ContactId contactId; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); - contactId = intent.getIntExtra(CONTACT_ID, -1); - if (contactId == -1) - throw new IllegalArgumentException("Wrong ContactId"); + int id = intent.getIntExtra(CONTACT_ID, -1); + if (id == -1) throw new IllegalStateException("No ContactId"); + contactId = new ContactId(id); setContentView(R.layout.activity_fragment_container); @@ -75,7 +76,7 @@ public class IntroductionActivity extends BriarActivity implements } } - int getContactId() { + ContactId getContactId() { return contactId; } diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java index bec5b346f..9a8f592e1 100644 --- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java +++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java @@ -37,9 +37,13 @@ public class AddContactActivity extends BriarActivity private static final Logger LOG = Logger.getLogger(AddContactActivity.class.getName()); - @Inject protected CryptoComponent crypto; - @Inject protected InvitationTaskFactory invitationTaskFactory; - @Inject protected ReferenceManager referenceManager; + @Inject + CryptoComponent crypto; + @Inject + InvitationTaskFactory invitationTaskFactory; + @Inject + ReferenceManager referenceManager; + private AddContactView view = null; private InvitationTask task = null; private long taskHandle = -1; @@ -52,7 +56,8 @@ public class AddContactActivity extends BriarActivity private String contactName = null; // Fields that are accessed from background threads must be volatile - @Inject protected volatile IdentityManager identityManager; + @Inject + volatile IdentityManager identityManager; @Override public void onCreate(Bundle state) { @@ -150,8 +155,8 @@ public class AddContactActivity extends BriarActivity } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); view.populate(); } diff --git a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java index 8ef2764cf..8a075f151 100644 --- a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java +++ b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java @@ -40,15 +40,13 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements private static final int STEP_QR = 2; @Inject - protected EventBus eventBus; - - private Toolbar toolbar; + EventBus eventBus; // Fields that are accessed from background threads must be volatile @Inject - protected volatile ContactExchangeTask contactExchangeTask; + volatile ContactExchangeTask contactExchangeTask; @Inject - protected volatile IdentityManager identityManager; + volatile IdentityManager identityManager; @Override public void injectActivity(ActivityComponent component) { @@ -61,7 +59,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements super.onCreate(state); setContentView(R.layout.activity_plain); - toolbar = (Toolbar) findViewById(R.id.toolbar); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -83,14 +81,14 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); eventBus.addListener(this); } @Override - protected void onPause() { - super.onPause(); + protected void onStop() { + super.onStop(); eventBus.removeListener(this); } diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java index cef537288..fc5d286b0 100644 --- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java +++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java @@ -162,25 +162,16 @@ public class ShowQrCodeFragment extends BaseEventFragment } else { startListening(); } - } - @Override - public void onResume() { - super.onResume(); openCamera(); } - @Override - public void onPause() { - super.onPause(); - releaseCamera(); - } - @Override public void onStop() { super.onStop(); stopListening(); if (receiver != null) getActivity().unregisterReceiver(receiver); + releaseCamera(); } @UiThread diff --git a/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java b/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java index 094eeaac2..f2f697394 100644 --- a/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java +++ b/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java @@ -132,16 +132,16 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); showPanicApp(PanicResponder.getTriggerPackageName(getActivity())); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java index fb0cd8ac5..8a6644efd 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java @@ -27,8 +27,8 @@ import java.util.logging.Logger; import javax.inject.Inject; -public class GroupControllerImpl - extends ThreadListControllerImpl +public class GroupControllerImpl extends + ThreadListControllerImpl implements GroupController { private static final Logger LOG = @@ -48,8 +48,8 @@ public class GroupControllerImpl } @Override - public void onActivityResume() { - super.onActivityResume(); + public void onActivityStart() { + super.onActivityStart(); // TODO: Add new notification manager methods for private groups } @@ -101,9 +101,8 @@ public class GroupControllerImpl @Override protected GroupMessage createLocalMessage(String body, long timestamp, @Nullable MessageId parentId, LocalAuthor author) { - return privateGroupManager - .createLocalMessage(getGroupId(), body, timestamp, parentId, - author); + return privateGroupManager.createLocalMessage(getGroupId(), body, + timestamp, parentId, author); } @Override diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java index 89b208b00..ac75f29cd 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java @@ -1,56 +1,51 @@ package org.briarproject.android.privategroup.list; +import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.identity.Author; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.sync.GroupId; -import org.jetbrains.annotations.NotNull; // This class is not thread-safe +@NotNullByDefault class GroupItem { private final PrivateGroup privateGroup; - private int messageCount; - private long lastUpdate; - private int unreadCount; + private int messageCount, unreadCount; + private long timestamp; private boolean dissolved; - GroupItem(@NotNull PrivateGroup privateGroup, int messageCount, - long lastUpdate, int unreadCount, boolean dissolved) { - + GroupItem(PrivateGroup privateGroup, GroupCount count, boolean dissolved) { this.privateGroup = privateGroup; - this.messageCount = messageCount; - this.lastUpdate = lastUpdate; - this.unreadCount = unreadCount; + this.messageCount = count.getMsgCount(); + this.unreadCount = count.getUnreadCount(); + this.timestamp = count.getLatestMsgTime(); this.dissolved = dissolved; } void addMessageHeader(GroupMessageHeader header) { messageCount++; - if (header.getTimestamp() > lastUpdate) { - lastUpdate = header.getTimestamp(); + if (header.getTimestamp() > timestamp) { + timestamp = header.getTimestamp(); } if (!header.isRead()) { unreadCount++; } } - @NotNull PrivateGroup getPrivateGroup() { return privateGroup; } - @NotNull GroupId getId() { return privateGroup.getId(); } - @NotNull Author getCreator() { return privateGroup.getAuthor(); } - @NotNull String getName() { return privateGroup.getName(); } @@ -63,8 +58,8 @@ class GroupItem { return messageCount; } - long getLastUpdate() { - return lastUpdate; + long getTimestamp() { + return timestamp; } int getUnreadCount() { diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java index bae48022a..b5588e344 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java @@ -38,7 +38,7 @@ class GroupListAdapter extends BriarAdapter { public int compare(GroupItem a, GroupItem b) { if (a == b) return 0; // The group with the latest message comes first - long aTime = a.getLastUpdate(), bTime = b.getLastUpdate(); + long aTime = a.getTimestamp(), bTime = b.getTimestamp(); if (aTime > bTime) return -1; if (aTime < bTime) return 1; // Break ties by group name @@ -50,7 +50,7 @@ class GroupListAdapter extends BriarAdapter { @Override public boolean areContentsTheSame(GroupItem a, GroupItem b) { return a.getMessageCount() == b.getMessageCount() && - a.getLastUpdate() == b.getLastUpdate() && + a.getTimestamp() == b.getTimestamp() && a.getUnreadCount() == b.getUnreadCount() && a.isDissolved() == b.isDissolved(); } diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java index 27e8c90d4..fbe05315d 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java @@ -31,6 +31,7 @@ public interface GroupListController extends DbController { ResultExceptionHandler result); interface GroupListListener extends DestroyableContext { + @UiThread void onGroupMessageAdded(GroupMessageHeader header); diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java index 9db84cdca..efa36fe5f 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java @@ -8,6 +8,7 @@ import org.briarproject.android.controller.handler.ResultExceptionHandler; import org.briarproject.api.clients.MessageTracker.GroupCount; import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DbException; +import org.briarproject.api.db.NoSuchGroupException; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; @@ -16,6 +17,7 @@ import org.briarproject.api.event.GroupMessageAddedEvent; import org.briarproject.api.event.GroupRemovedEvent; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroupManager; import org.briarproject.api.sync.ClientId; @@ -29,6 +31,7 @@ import java.util.logging.Logger; import javax.inject.Inject; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; public class GroupListControllerImpl extends DbControllerImpl @@ -81,59 +84,77 @@ public class GroupListControllerImpl extends DbControllerImpl @CallSuper public void eventOccurred(Event e) { if (e instanceof GroupMessageAddedEvent) { - final GroupMessageAddedEvent m = (GroupMessageAddedEvent) e; - LOG.info("New group message added"); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onGroupMessageAdded(m.getHeader()); - } - }); + GroupMessageAddedEvent g = (GroupMessageAddedEvent) e; + LOG.info("Private group message added"); + onGroupMessageAdded(g.getHeader()); } else if (e instanceof GroupAddedEvent) { - final GroupAddedEvent gae = (GroupAddedEvent) e; - ClientId id = gae.getGroup().getClientId(); + GroupAddedEvent g = (GroupAddedEvent) e; + ClientId id = g.getGroup().getClientId(); if (id.equals(groupManager.getClientId())) { LOG.info("Private group added"); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onGroupAdded(gae.getGroup().getId()); - } - }); + onGroupAdded(g.getGroup().getId()); } } else if (e instanceof GroupRemovedEvent) { - final GroupRemovedEvent gre = (GroupRemovedEvent) e; - ClientId id = gre.getGroup().getClientId(); + GroupRemovedEvent g = (GroupRemovedEvent) e; + ClientId id = g.getGroup().getClientId(); if (id.equals(groupManager.getClientId())) { LOG.info("Private group removed"); - listener.runOnUiThreadUnlessDestroyed(new Runnable() { - @Override - public void run() { - listener.onGroupRemoved(gre.getGroup().getId()); - } - }); + onGroupRemoved(g.getGroup().getId()); } } } + private void onGroupMessageAdded(final GroupMessageHeader h) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupMessageAdded(h); + } + }); + } + + private void onGroupAdded(final GroupId g) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupAdded(g); + } + }); + } + + private void onGroupRemoved(final GroupId g) { + listener.runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + listener.onGroupRemoved(g); + } + }); + } + @Override public void loadGroups( final ResultExceptionHandler, DbException> handler) { runOnDbThread(new Runnable() { @Override public void run() { - LOG.info("Loading groups from database..."); try { + long now = System.currentTimeMillis(); Collection groups = groupManager.getPrivateGroups(); List items = new ArrayList<>(groups.size()); for (PrivateGroup g : groups) { - GroupCount c = groupManager.getGroupCount(g.getId()); - boolean dissolved = groupManager.isDissolved(g.getId()); - items.add(new GroupItem(g, c.getMsgCount(), - c.getLatestMsgTime(), c.getUnreadCount(), - dissolved)); + try { + GroupId id = g.getId(); + GroupCount count = groupManager.getGroupCount(id); + boolean dissolved = groupManager.isDissolved(id); + items.add(new GroupItem(g, count, dissolved)); + } catch (NoSuchGroupException e) { + // Continue + } } + long duration = System.currentTimeMillis() - now; + if (LOG.isLoggable(INFO)) + LOG.info("Loading groups took " + duration + " ms"); handler.onResult(items); } catch (DbException e) { if (LOG.isLoggable(WARNING)) @@ -150,9 +171,13 @@ public class GroupListControllerImpl extends DbControllerImpl runOnDbThread(new Runnable() { @Override public void run() { - LOG.info("Removing group from database..."); try { + long now = System.currentTimeMillis(); groupManager.removePrivateGroup(g); + long duration = System.currentTimeMillis() - now; + if (LOG.isLoggable(INFO)) + LOG.info("Removing group took " + duration + " ms"); + handler.onResult(null); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java index bf773c28c..a786e766c 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java @@ -1,6 +1,5 @@ package org.briarproject.android.privategroup.list; -import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.annotation.UiThread; @@ -16,7 +15,6 @@ import org.briarproject.R; import org.briarproject.android.ActivityComponent; import org.briarproject.android.controller.handler.UiResultExceptionHandler; import org.briarproject.android.fragment.BaseFragment; -import org.briarproject.android.invitation.AddContactActivity; import org.briarproject.android.privategroup.list.GroupListController.GroupListListener; import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener; import org.briarproject.android.view.BriarRecyclerView; @@ -152,12 +150,9 @@ public class GroupListFragment extends BaseFragment implements new UiResultExceptionHandler, DbException>( listener) { @Override - public void onResultUi(Collection result) { - if (result.isEmpty()) { - list.showData(); - } else { - adapter.addAll(result); - } + public void onResultUi(Collection groups) { + if (groups.isEmpty()) list.showData(); + else adapter.addAll(groups); } @Override diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java index c7d59dd1f..7f3031aec 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java @@ -88,7 +88,7 @@ class GroupViewHolder extends RecyclerView.ViewHolder { postCount.setTextColor( getColor(ctx, R.color.briar_text_secondary)); - long lastUpdate = group.getLastUpdate(); + long lastUpdate = group.getTimestamp(); date.setText(AndroidUtils.formatDate(ctx, lastUpdate)); date.setVisibility(VISIBLE); avatar.setProblem(false); diff --git a/briar-android/src/org/briarproject/android/report/DevReportActivity.java b/briar-android/src/org/briarproject/android/report/DevReportActivity.java index 919a0b620..0d142757e 100644 --- a/briar-android/src/org/briarproject/android/report/DevReportActivity.java +++ b/briar-android/src/org/briarproject/android/report/DevReportActivity.java @@ -163,8 +163,8 @@ public class DevReportActivity extends BaseCrashReportDialog } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); if (chevron.isSelected()) refresh(); } diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java index 8e270d640..82db75adf 100644 --- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java +++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java @@ -30,7 +30,6 @@ import org.briarproject.api.sync.GroupId; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.logging.Logger; @@ -57,11 +56,11 @@ public class ContactSelectorFragment extends BaseFragment implements // Fields that are accessed from background threads must be volatile @Inject - protected volatile ContactManager contactManager; + volatile ContactManager contactManager; @Inject - protected volatile IdentityManager identityManager; + volatile IdentityManager identityManager; @Inject - protected volatile ForumSharingManager forumSharingManager; + volatile ForumSharingManager forumSharingManager; private volatile GroupId groupId; @@ -91,8 +90,9 @@ public class ContactSelectorFragment extends BaseFragment implements setHasOptionsMenu(true); Bundle args = getArguments(); - groupId = new GroupId(args.getByteArray(GROUP_ID)); - if (groupId == null) throw new IllegalStateException("No GroupId"); + byte[] b = args.getByteArray(GROUP_ID); + if (b == null) throw new IllegalStateException("No GroupId"); + groupId = new GroupId(b); } @Override @@ -125,12 +125,16 @@ public class ContactSelectorFragment extends BaseFragment implements } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); + loadContacts(selectedContacts); + } - if (selectedContacts != null) - loadContacts(Collections.unmodifiableCollection(selectedContacts)); - else loadContacts(null); + @Override + public void onStop() { + super.onStop(); + adapter.clear(); + list.showProgressBar(); } @Override @@ -202,9 +206,8 @@ public class ContactSelectorFragment extends BaseFragment implements long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Load took " + duration + " ms"); - displayContacts(Collections.unmodifiableList(contacts)); + displayContacts(contacts); } catch (DbException e) { - displayContacts(Collections.emptyList()); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } @@ -216,8 +219,8 @@ public class ContactSelectorFragment extends BaseFragment implements shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (!contacts.isEmpty()) adapter.addAll(contacts); - else list.showData(); + if (contacts.isEmpty()) list.showData(); + else adapter.addAll(contacts); updateMenuItem(); } }); diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java index a6b33a0d8..fc691ac2b 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java @@ -2,6 +2,7 @@ package org.briarproject.android.sharing; import android.content.Context; import android.os.Bundle; +import android.support.annotation.CallSuper; import android.support.v7.widget.LinearLayoutManager; import android.widget.Toast; @@ -42,7 +43,6 @@ abstract class InvitationsActivity extends BriarActivity adapter = getAdapter(this, this); - list = (BriarRecyclerView) findViewById(R.id.list); if (list != null) { list.setLayoutManager(new LinearLayoutManager(this)); @@ -51,21 +51,22 @@ abstract class InvitationsActivity extends BriarActivity } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); eventBus.addListener(this); loadInvitations(false); } @Override - public void onPause() { - super.onPause(); + public void onStop() { + super.onStop(); eventBus.removeListener(this); adapter.clear(); list.showProgressBar(); } @Override + @CallSuper public void eventOccurred(Event e) { if (e instanceof ContactRemovedEvent) { LOG.info("Contact removed, reloading..."); @@ -110,8 +111,8 @@ abstract class InvitationsActivity extends BriarActivity LOG.info("No more invitations available, finishing"); finish(); } else { - if (clear) adapter.clear(); - adapter.addAll(invitations); + if (clear) adapter.setItems(invitations); + else adapter.addAll(invitations); } } }); diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java index 58e818269..014391d5b 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java @@ -29,9 +29,9 @@ public class InvitationsBlogActivity extends InvitationsActivity { // Fields that are accessed from background threads must be volatile @Inject - protected volatile BlogManager blogManager; + volatile BlogManager blogManager; @Inject - protected volatile BlogSharingManager blogSharingManager; + volatile BlogSharingManager blogSharingManager; @Override public void injectActivity(ActivityComponent component) { @@ -62,31 +62,34 @@ public class InvitationsBlogActivity extends InvitationsActivity { } } + @Override protected InvitationAdapter getAdapter(Context ctx, AvailableForumClickListener listener) { return new BlogInvitationAdapter(ctx, listener); } + @Override protected void loadInvitations(final boolean clear) { runOnDbThread(new Runnable() { @Override public void run() { - Collection invitations = new ArrayList<>(); try { + Collection invitations = new ArrayList<>(); long now = System.currentTimeMillis(); invitations.addAll(blogSharingManager.getInvitations()); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Load took " + duration + " ms"); + displayInvitations(invitations, clear); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } - displayInvitations(invitations, clear); } }); } + @Override protected void respondToInvitation(final InvitationItem item, final boolean accept) { runOnDbThread(new Runnable() { @@ -95,6 +98,7 @@ public class InvitationsBlogActivity extends InvitationsActivity { try { Blog b = (Blog) item.getShareable(); for (Contact c : item.getNewSharers()) { + // TODO: What happens if a contact has been removed? blogSharingManager.respondToInvitation(b, c, accept); } } catch (DbException e) { @@ -105,10 +109,12 @@ public class InvitationsBlogActivity extends InvitationsActivity { }); } + @Override protected int getAcceptRes() { return R.string.blogs_sharing_joined_toast; } + @Override protected int getDeclineRes() { return R.string.blogs_sharing_declined_toast; } diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java index 51ddcc838..6b5811eaa 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java @@ -29,9 +29,9 @@ public class InvitationsForumActivity extends InvitationsActivity { // Fields that are accessed from background threads must be volatile @Inject - protected volatile ForumManager forumManager; + volatile ForumManager forumManager; @Inject - protected volatile ForumSharingManager forumSharingManager; + volatile ForumSharingManager forumSharingManager; @Override public void injectActivity(ActivityComponent component) { @@ -62,31 +62,34 @@ public class InvitationsForumActivity extends InvitationsActivity { } } + @Override protected InvitationAdapter getAdapter(Context ctx, AvailableForumClickListener listener) { return new ForumInvitationAdapter(ctx, listener); } + @Override protected void loadInvitations(final boolean clear) { runOnDbThread(new Runnable() { @Override public void run() { - Collection invitations = new ArrayList<>(); try { + Collection invitations = new ArrayList<>(); long now = System.currentTimeMillis(); invitations.addAll(forumSharingManager.getInvitations()); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Load took " + duration + " ms"); + displayInvitations(invitations, clear); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } - displayInvitations(invitations, clear); } }); } + @Override protected void respondToInvitation(final InvitationItem item, final boolean accept) { runOnDbThread(new Runnable() { @@ -95,6 +98,7 @@ public class InvitationsForumActivity extends InvitationsActivity { try { Forum f = (Forum) item.getShareable(); for (Contact c : item.getNewSharers()) { + // TODO: What happens if a contact has been removed? forumSharingManager.respondToInvitation(f, c, accept); } } catch (DbException e) { @@ -105,10 +109,12 @@ public class InvitationsForumActivity extends InvitationsActivity { }); } + @Override protected int getAcceptRes() { return R.string.forum_joined_toast; } + @Override protected int getDeclineRes() { return R.string.forum_declined_toast; } diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java index 969d525a3..377b10d71 100644 --- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java @@ -63,13 +63,21 @@ abstract class SharingStatusActivity extends BriarActivity { } @Override - public void onResume() { - super.onResume(); - + public void onStart() { + super.onStart(); loadSharedBy(); loadSharedWith(); } + @Override + public void onStop() { + super.onStop(); + sharedByAdapter.clear(); + sharedByList.showProgressBar(); + sharedWithAdapter.clear(); + sharedWithList.showProgressBar(); + } + @Override public boolean onOptionsItemSelected(final MenuItem item) { // Handle presses on the action bar items @@ -97,11 +105,11 @@ abstract class SharingStatusActivity extends BriarActivity { } private void loadSharedBy() { - dbController.runOnDbThread(new Runnable() { + runOnDbThread(new Runnable() { @Override public void run() { - List contactItems = new ArrayList<>(); try { + List contactItems = new ArrayList<>(); for (Contact c : getSharedBy()) { LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); @@ -110,11 +118,11 @@ abstract class SharingStatusActivity extends BriarActivity { groupId, new GroupCount(0, 0, 0)); contactItems.add(item); } + displaySharedBy(contactItems); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } - displaySharedBy(contactItems); } }); } @@ -123,21 +131,18 @@ abstract class SharingStatusActivity extends BriarActivity { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (contacts.isEmpty()) { - sharedByList.showData(); - } else { - sharedByAdapter.addAll(contacts); - } + if (contacts.isEmpty()) sharedByList.showData(); + else sharedByAdapter.addAll(contacts); } }); } private void loadSharedWith() { - dbController.runOnDbThread(new Runnable() { + runOnDbThread(new Runnable() { @Override public void run() { - List contactItems = new ArrayList<>(); try { + List contactItems = new ArrayList<>(); for (Contact c : getSharedWith()) { LocalAuthor localAuthor = identityManager .getLocalAuthor(c.getLocalAuthorId()); @@ -146,11 +151,11 @@ abstract class SharingStatusActivity extends BriarActivity { groupId, new GroupCount(0, 0, 0)); contactItems.add(item); } + displaySharedWith(contactItems); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } - displaySharedWith(contactItems); } }); } @@ -159,11 +164,8 @@ abstract class SharingStatusActivity extends BriarActivity { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (contacts.isEmpty()) { - sharedWithList.showData(); - } else { - sharedWithAdapter.addAll(contacts); - } + if (contacts.isEmpty()) sharedWithList.showData(); + else sharedWithAdapter.addAll(contacts); } }); } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java index 889399525..5ae9b5c6f 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java @@ -75,7 +75,7 @@ public abstract class ThreadListActivity bodyCache = - new ConcurrentHashMap<>(); + private final Map bodyCache = new ConcurrentHashMap<>(); private volatile GroupId groupId; @@ -82,14 +81,14 @@ public abstract class ThreadListControllerImpl this.items.addAll(items); } + public void setItems(Collection items) { + this.items.beginBatchedUpdates(); + this.items.clear(); + this.items.addAll(items); + this.items.endBatchedUpdates(); + } + @Nullable public T getItemAt(int position) { if (position == INVALID_POSITION || position >= items.size()) { diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java b/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java index 3d531c4e0..f1002e66b 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java @@ -1,17 +1,25 @@ package org.briarproject.api.crypto; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; -/** Annotation for injecting the executor for long-running crypto tasks. */ +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation for injecting the executor for long-running crypto tasks. Also + * used for annotating methods that should run on the crypto executor. + *

+ * The contract of this executor is that tasks may be run concurrently, and + * submitting a task will never block. Tasks must not run indefinitely. Tasks + * submitted during shutdown are discarded. + */ @Qualifier @Target({FIELD, METHOD, PARAMETER}) @Retention(RUNTIME) -public @interface CryptoExecutor {} +public @interface CryptoExecutor { +} diff --git a/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java b/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java index f682121d0..5421f451f 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java @@ -1,21 +1,23 @@ package org.briarproject.api.db; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + /** - * Annotation for injecting the executor for database tasks. + * Annotation for injecting the executor for database tasks. Also used for + * annotating methods that should run on the database executor. *

- * The contract of this executor is that tasks are executed in the order - * they're submitted, tasks are not executed concurrently, and submitting a - * task will never block. + * The contract of this executor is that tasks are run in the order they're + * submitted, tasks are not run concurrently, and submitting a task will never + * block. Tasks must not run indefinitely. Tasks submitted during shutdown are + * discarded. */ @Qualifier @Target({ FIELD, METHOD, PARAMETER }) diff --git a/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java index 04f7f9164..e1ddbfd19 100644 --- a/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java @@ -1,5 +1,6 @@ package org.briarproject.api.event; +import org.briarproject.api.contact.ContactId; import org.briarproject.api.messaging.PrivateMessageHeader; import org.briarproject.api.sync.GroupId; @@ -9,11 +10,13 @@ import org.briarproject.api.sync.GroupId; public class PrivateMessageReceivedEvent extends Event { private final PrivateMessageHeader messageHeader; + private final ContactId contactId; private final GroupId groupId; public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader, - GroupId groupId) { + ContactId contactId, GroupId groupId) { this.messageHeader = messageHeader; + this.contactId = contactId; this.groupId = groupId; } @@ -21,6 +24,10 @@ public class PrivateMessageReceivedEvent extends Event { return messageHeader; } + public ContactId getContactId() { + return contactId; + } + public GroupId getGroupId() { return groupId; } diff --git a/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java b/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java index 02bc5bf87..1bffc3c3c 100644 --- a/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java +++ b/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java @@ -1,17 +1,25 @@ package org.briarproject.api.lifecycle; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; -/** Annotation for injecting the executor used by long-lived IO tasks. */ +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation for injecting the executor for long-running IO tasks. Also used + * for annotating methods that should run on the UI executor. + *

+ * The contract of this executor is that tasks may be run concurrently, and + * submitting a task will never block. Tasks may run indefinitely. Tasks + * submitted during shutdown are discarded. + */ @Qualifier -@Target({ FIELD, METHOD, PARAMETER }) +@Target({FIELD, METHOD, PARAMETER}) @Retention(RUNTIME) -public @interface IoExecutor {} \ No newline at end of file +public @interface IoExecutor { +} \ No newline at end of file diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java index 8a591849a..a8fa365cb 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java @@ -102,10 +102,11 @@ class MessagingManagerImpl extends ConversationClientImpl boolean local = meta.getBoolean("local"); boolean read = meta.getBoolean(MSG_KEY_READ); PrivateMessageHeader header = new PrivateMessageHeader( - m.getId(), m.getGroupId(), timestamp, contentType, local, read, + m.getId(), groupId, timestamp, contentType, local, read, false, false); + ContactId contactId = getContactId(txn, groupId); PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent( - header, groupId); + header, contactId, groupId); txn.attach(event); trackIncomingMessage(txn, m); @@ -133,6 +134,17 @@ class MessagingManagerImpl extends ConversationClientImpl } } + private ContactId getContactId(Transaction txn, GroupId g) + throws DbException { + try { + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g); + return new ContactId(meta.getLong("contactId").intValue()); + } catch (FormatException e) { + throw new DbException(e); + } + } + @Override public ContactId getContactId(GroupId g) throws DbException { try { From 2140a290e4e2080dd09ecf024860a9171cfcc336 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 17 Oct 2016 10:54:00 +0100 Subject: [PATCH 2/5] Avoid race conditions when updating the UI from events. --- .../android/blogs/BlogFragment.java | 18 ++- .../android/blogs/FeedFragment.java | 16 ++- .../android/blogs/RssFeedManageActivity.java | 29 ++++- .../android/contact/ContactListFragment.java | 19 ++- .../android/contact/ConversationActivity.java | 114 ++++++++++-------- .../android/forum/ForumActivity.java | 5 +- .../android/forum/ForumListFragment.java | 18 ++- .../privategroup/list/GroupListFragment.java | 15 ++- .../android/sharing/InvitationsActivity.java | 11 +- .../sharing/InvitationsBlogActivity.java | 3 +- .../sharing/InvitationsForumActivity.java | 3 +- .../android/threaded/ThreadItemAdapter.java | 29 ++++- .../android/threaded/ThreadListActivity.java | 27 +++-- .../android/util/BriarAdapter.java | 25 ++++ 14 files changed, 239 insertions(+), 93 deletions(-) diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index eb6552091..d70bdb14e 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -32,6 +32,7 @@ import org.briarproject.api.identity.Author; import org.briarproject.api.sync.GroupId; import java.util.Collection; +import java.util.logging.Logger; import javax.inject.Inject; @@ -51,6 +52,7 @@ public class BlogFragment extends BaseFragment implements OnBlogPostAddedListener { public final static String TAG = BlogFragment.class.getName(); + private static final Logger LOG = Logger.getLogger(TAG); @Inject BlogController blogController; @@ -207,6 +209,7 @@ public class BlogFragment extends BaseFragment implements listener) { @Override public void onResultUi(BlogPostItem post) { + adapter.incrementRevision(); adapter.add(post); if (local) { list.scrollToPosition(0); @@ -228,16 +231,23 @@ public class BlogFragment extends BaseFragment implements } void loadBlogPosts(final boolean reload) { + final int revision = adapter.getRevision(); blogController.loadBlogPosts( new UiResultExceptionHandler, DbException>( listener) { @Override public void onResultUi(Collection posts) { - if (posts.isEmpty()) { - list.showData(); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (posts.isEmpty()) { + list.showData(); + } else { + adapter.addAll(posts); + if (reload) list.scrollToPosition(0); + } } else { - adapter.addAll(posts); - if (reload) list.scrollToPosition(0); + LOG.info("Concurrent update, reloading"); + loadBlogPosts(reload); } } diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index 6f960d3c1..cf9784160 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -27,6 +27,7 @@ import org.briarproject.api.blogs.BlogPostHeader; import org.briarproject.api.db.DbException; import java.util.Collection; +import java.util.logging.Logger; import javax.inject.Inject; @@ -41,6 +42,7 @@ public class FeedFragment extends BaseFragment implements OnBlogPostClickListener, OnBlogPostAddedListener { public final static String TAG = FeedFragment.class.getName(); + private static final Logger LOG = Logger.getLogger(TAG); @Inject FeedController feedController; @@ -129,14 +131,21 @@ public class FeedFragment extends BaseFragment implements } private void loadBlogPosts(final boolean clear) { + final int revision = adapter.getRevision(); feedController.loadBlogPosts( new UiResultExceptionHandler, DbException>( listener) { @Override public void onResultUi(Collection posts) { - if (clear) adapter.setItems(posts); - else adapter.addAll(posts); - if (posts.isEmpty()) list.showData(); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (clear) adapter.setItems(posts); + else adapter.addAll(posts); + if (posts.isEmpty()) list.showData(); + } else { + LOG.info("Concurrent update, reloading"); + loadBlogPosts(clear); + } } @Override @@ -193,6 +202,7 @@ public class FeedFragment extends BaseFragment implements listener) { @Override public void onResultUi(BlogPostItem post) { + adapter.incrementRevision(); adapter.add(post); if (local) { showSnackBar(R.string.blogs_blog_post_created); diff --git a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java index 0eb6df792..ecffd0cd2 100644 --- a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java +++ b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java @@ -125,27 +125,43 @@ public class RssFeedManageActivity extends BriarActivity } private void loadFeeds() { + final int revision = adapter.getRevision(); runOnDbThread(new Runnable() { @Override public void run() { try { - addFeeds(feedManager.getFeeds()); + displayFeeds(revision, feedManager.getFeeds()); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - list.setEmptyText(R.string.blogs_rss_feeds_manage_error); - list.showData(); + onLoadError(); } } }); } - private void addFeeds(final List feeds) { + private void displayFeeds(final int revision, final List feeds) { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (feeds.isEmpty()) list.showData(); - else adapter.addAll(feeds); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (feeds.isEmpty()) list.showData(); + else adapter.addAll(feeds); + } else { + LOG.info("Concurrent update, reloading"); + loadFeeds(); + } + } + }); + } + + private void onLoadError() { + runOnUiThreadUnlessDestroyed(new Runnable() { + @Override + public void run() { + list.setEmptyText(R.string.blogs_rss_feeds_manage_error); + list.showData(); } }); } @@ -154,6 +170,7 @@ public class RssFeedManageActivity extends BriarActivity runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); adapter.remove(feed); } }); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index d640439a6..474b2cc2b 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -190,6 +190,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { } private void loadContacts() { + final int revision = adapter.getRevision(); listener.runOnDbThread(new Runnable() { @Override public void run() { @@ -216,7 +217,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Full load took " + duration + " ms"); - displayContacts(contacts); + displayContacts(revision, contacts); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -225,12 +226,19 @@ public class ContactListFragment extends BaseFragment implements EventListener { }); } - private void displayContacts(final List contacts) { + private void displayContacts(final int revision, + final List contacts) { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (contacts.isEmpty()) list.showData(); - else adapter.addAll(contacts); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (contacts.isEmpty()) list.showData(); + else adapter.addAll(contacts); + } else { + LOG.info("Concurrent update, reloading"); + loadContacts(); + } } }); } @@ -288,6 +296,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); int position = adapter.findItemPosition(c); ContactListItem item = adapter.getItemAt(position); if (item != null) { @@ -302,6 +311,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); int position = adapter.findItemPosition(c); ContactListItem item = adapter.getItemAt(position); if (item != null) adapter.remove(item); @@ -313,6 +323,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); int position = adapter.findItemPosition(c); ContactListItem item = adapter.getItemAt(position); if (item != null) { diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index fd948d0aa..c92c51951 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -289,12 +289,10 @@ public class ConversationActivity extends BriarActivity contactIdenticonKey = contact.getAuthor().getId().getBytes(); } - boolean connected = - connectionRegistry.isConnected(contactId); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading contact took " + duration + " ms"); - displayContactDetails(connected); + displayContactDetails(); } catch (NoSuchContactException e) { finishOnUiThread(); } catch (DbException e) { @@ -305,7 +303,7 @@ public class ConversationActivity extends BriarActivity }); } - private void displayContactDetails(final boolean connected) { + private void displayContactDetails() { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { @@ -313,7 +311,7 @@ public class ConversationActivity extends BriarActivity new IdenticonDrawable(contactIdenticonKey)); toolbarTitle.setText(contactName); - if (connected) { + if (connectionRegistry.isConnected(contactId)) { toolbarStatus.setImageDrawable(ContextCompat .getDrawable(ConversationActivity.this, R.drawable.contact_online)); @@ -332,6 +330,7 @@ public class ConversationActivity extends BriarActivity } private void loadMessages() { + final int revision = adapter.getRevision(); runOnDbThread(new Runnable() { @Override public void run() { @@ -357,7 +356,8 @@ public class ConversationActivity extends BriarActivity long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading messages took " + duration + " ms"); - displayMessages(headers, introductions, invitations); + displayMessages(revision, headers, introductions, + invitations); } catch (NoSuchContactException e) { finishOnUiThread(); } catch (DbException e) { @@ -368,56 +368,66 @@ public class ConversationActivity extends BriarActivity }); } - private void displayMessages(final Collection headers, + private void displayMessages(final int revision, + final Collection headers, final Collection introductions, final Collection invitations) { runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - textInputView.setSendButtonEnabled(true); - int size = headers.size() + introductions.size() + - invitations.size(); - if (size == 0) { - list.showData(); - } else { - List items = new ArrayList<>(size); - for (PrivateMessageHeader h : headers) { - ConversationMessageItem item = ConversationItem.from(h); - byte[] body = bodyCache.get(h.getId()); - if (body == null) loadMessageBody(h.getId()); - else item.setBody(body); - items.add(item); - } - for (IntroductionMessage im : introductions) { - if (im instanceof IntroductionRequest) { - IntroductionRequest ir = (IntroductionRequest) im; - items.add(ConversationItem.from(ir)); - } else { - IntroductionResponse ir = (IntroductionResponse) im; - items.add(ConversationItem - .from(ConversationActivity.this, - contactName, ir)); - } - } - for (InvitationMessage im : invitations) { - if (im instanceof InvitationRequest) { - InvitationRequest ir = (InvitationRequest) im; - items.add(ConversationItem.from(ir)); - } else if (im instanceof InvitationResponse) { - InvitationResponse ir = (InvitationResponse) im; - items.add(ConversationItem - .from(ConversationActivity.this, - contactName, ir)); - } - } - adapter.addAll(items); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + textInputView.setSendButtonEnabled(true); + List items = createItems(headers, + introductions, invitations); + if (items.isEmpty()) list.showData(); + else adapter.addAll(items); // Scroll to the bottom list.scrollToPosition(adapter.getItemCount() - 1); + } else { + LOG.info("Concurrent update, reloading"); + loadMessages(); } } }); } + private List createItems( + Collection headers, + Collection introductions, + Collection invitations) { + int size = headers.size() + introductions.size() + invitations.size(); + List items = new ArrayList<>(size); + for (PrivateMessageHeader h : headers) { + ConversationMessageItem item = ConversationItem.from(h); + byte[] body = bodyCache.get(h.getId()); + if (body == null) loadMessageBody(h.getId()); + else item.setBody(body); + items.add(item); + } + for (IntroductionMessage im : introductions) { + if (im instanceof IntroductionRequest) { + IntroductionRequest ir = (IntroductionRequest) im; + items.add(ConversationItem.from(ir)); + } else { + IntroductionResponse ir = (IntroductionResponse) im; + items.add(ConversationItem.from(ConversationActivity.this, + contactName, ir)); + } + } + for (InvitationMessage im : invitations) { + if (im instanceof InvitationRequest) { + InvitationRequest ir = (InvitationRequest) im; + items.add(ConversationItem.from(ir)); + } else if (im instanceof InvitationResponse) { + InvitationResponse ir = (InvitationResponse) im; + items.add(ConversationItem.from(ConversationActivity.this, + contactName, ir)); + } + } + return items; + } + private void loadMessageBody(final MessageId m) { runOnDbThread(new Runnable() { @Override @@ -461,6 +471,7 @@ public class ConversationActivity extends BriarActivity runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); adapter.add(item); // Scroll to the bottom list.scrollToPosition(adapter.getItemCount() - 1); @@ -535,13 +546,13 @@ public class ConversationActivity extends BriarActivity ContactConnectedEvent c = (ContactConnectedEvent) e; if (c.getContactId().equals(contactId)) { LOG.info("Contact connected"); - displayContactDetails(true); + displayContactDetails(); } } else if (e instanceof ContactDisconnectedEvent) { ContactDisconnectedEvent c = (ContactDisconnectedEvent) e; if (c.getContactId().equals(contactId)) { LOG.info("Contact disconnected"); - displayContactDetails(false); + displayContactDetails(); } } else if (e instanceof IntroductionRequestReceivedEvent) { IntroductionRequestReceivedEvent event = @@ -589,6 +600,7 @@ public class ConversationActivity extends BriarActivity runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); Set messages = new HashSet<>(messageIds); SparseArray list = adapter.getOutgoingMessages(); for (int i = 0; i < list.size(); i++) { @@ -807,13 +819,11 @@ public class ConversationActivity extends BriarActivity timestamp = Math.max(timestamp, getMinTimestampForNewMessage()); try { if (accept) { - introductionManager - .acceptIntroduction(contactId, sessionId, - timestamp); + introductionManager.acceptIntroduction(contactId, + sessionId, timestamp); } else { - introductionManager - .declineIntroduction(contactId, sessionId, - timestamp); + introductionManager.declineIntroduction(contactId, + sessionId, timestamp); } loadMessages(); } catch (DbException | FormatException e) { diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 03ebdf438..12487efc9 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -147,7 +147,7 @@ public class ForumActivity extends private void showUnsubscribeDialog() { OnClickListener okListener = new OnClickListener() { @Override - public void onClick(final DialogInterface dialog, int which) { + public void onClick(DialogInterface dialog, int which) { deleteNamedGroup(); } }; @@ -162,8 +162,7 @@ public class ForumActivity extends private void deleteNamedGroup() { forumController.deleteNamedGroup( - new UiResultExceptionHandler( - ForumActivity.this) { + new UiResultExceptionHandler(this) { @Override public void onResultUi(Void v) { Toast.makeText(ForumActivity.this, diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index 0edb1a075..6bbf19657 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -150,6 +150,7 @@ public class ForumListFragment extends BaseEventFragment implements } private void loadForums() { + final int revision = adapter.getRevision(); listener.runOnDbThread(new Runnable() { @Override public void run() { @@ -168,7 +169,7 @@ public class ForumListFragment extends BaseEventFragment implements long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Full load took " + duration + " ms"); - displayForums(forums); + displayForums(revision, forums); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -177,12 +178,19 @@ public class ForumListFragment extends BaseEventFragment implements }); } - private void displayForums(final Collection forums) { + private void displayForums(final int revision, + final Collection forums) { listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - if (forums.isEmpty()) list.showData(); - else adapter.addAll(forums); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (forums.isEmpty()) list.showData(); + else adapter.addAll(forums); + } else { + LOG.info("Concurrent update, reloading"); + loadForums(); + } } }); } @@ -254,6 +262,7 @@ public class ForumListFragment extends BaseEventFragment implements listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); int position = adapter.findItemPosition(g); ForumListItem item = adapter.getItemAt(position); if (item != null) { @@ -268,6 +277,7 @@ public class ForumListFragment extends BaseEventFragment implements listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { + adapter.incrementRevision(); int position = adapter.findItemPosition(g); ForumListItem item = adapter.getItemAt(position); if (item != null) adapter.remove(item); diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java index a786e766c..551c8f30b 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java @@ -23,6 +23,7 @@ import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.sync.GroupId; import java.util.Collection; +import java.util.logging.Logger; import javax.inject.Inject; @@ -30,6 +31,7 @@ public class GroupListFragment extends BaseFragment implements GroupListListener, OnGroupRemoveClickListener { public final static String TAG = GroupListFragment.class.getName(); + private static final Logger LOG = Logger.getLogger(TAG); public static GroupListFragment newInstance() { return new GroupListFragment(); @@ -120,6 +122,7 @@ public class GroupListFragment extends BaseFragment implements @UiThread @Override public void onGroupMessageAdded(GroupMessageHeader header) { + adapter.incrementRevision(); int position = adapter.findItemPosition(header.getGroupId()); GroupItem item = adapter.getItemAt(position); if (item != null) { @@ -137,6 +140,7 @@ public class GroupListFragment extends BaseFragment implements @UiThread @Override public void onGroupRemoved(GroupId groupId) { + adapter.incrementRevision(); adapter.removeItem(groupId); } @@ -146,13 +150,20 @@ public class GroupListFragment extends BaseFragment implements } private void loadGroups() { + final int revision = adapter.getRevision(); controller.loadGroups( new UiResultExceptionHandler, DbException>( listener) { @Override public void onResultUi(Collection groups) { - if (groups.isEmpty()) list.showData(); - else adapter.addAll(groups); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (groups.isEmpty()) list.showData(); + else adapter.addAll(groups); + } else { + LOG.info("Concurrent update, reloading"); + loadGroups(); + } } @Override diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java index fc691ac2b..772be9bf6 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java @@ -29,7 +29,7 @@ abstract class InvitationsActivity extends BriarActivity protected static final Logger LOG = Logger.getLogger(InvitationsActivity.class.getName()); - private InvitationAdapter adapter; + protected InvitationAdapter adapter; private BriarRecyclerView list; @Inject @@ -84,6 +84,7 @@ abstract class InvitationsActivity extends BriarActivity Toast.makeText(this, res, LENGTH_SHORT).show(); // remove item and finish if it was the last + adapter.incrementRevision(); adapter.remove(item); if (adapter.getItemCount() == 0) { supportFinishAfterTransition(); @@ -102,7 +103,7 @@ abstract class InvitationsActivity extends BriarActivity abstract protected int getDeclineRes(); - protected void displayInvitations( + protected void displayInvitations(final int revision, final Collection invitations, final boolean clear) { runOnUiThreadUnlessDestroyed(new Runnable() { @Override @@ -110,9 +111,13 @@ abstract class InvitationsActivity extends BriarActivity if (invitations.isEmpty()) { LOG.info("No more invitations available, finishing"); finish(); - } else { + } else if (revision == adapter.getRevision()) { + adapter.incrementRevision(); if (clear) adapter.setItems(invitations); else adapter.addAll(invitations); + } else { + LOG.info("Concurrent update, reloading"); + loadInvitations(clear); } } }); diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java index 014391d5b..1b0e5f3bd 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java @@ -70,6 +70,7 @@ public class InvitationsBlogActivity extends InvitationsActivity { @Override protected void loadInvitations(final boolean clear) { + final int revision = adapter.getRevision(); runOnDbThread(new Runnable() { @Override public void run() { @@ -80,7 +81,7 @@ public class InvitationsBlogActivity extends InvitationsActivity { long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Load took " + duration + " ms"); - displayInvitations(invitations, clear); + displayInvitations(revision, invitations, clear); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java index 6b5811eaa..d64dab69f 100644 --- a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java +++ b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java @@ -70,6 +70,7 @@ public class InvitationsForumActivity extends InvitationsActivity { @Override protected void loadInvitations(final boolean clear) { + final int revision = adapter.getRevision(); runOnDbThread(new Runnable() { @Override public void run() { @@ -80,7 +81,7 @@ public class InvitationsForumActivity extends InvitationsActivity { long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Load took " + duration + " ms"); - displayInvitations(invitations, clear); + displayInvitations(revision, invitations, clear); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java index f089f7c7e..034b6924f 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java @@ -24,13 +24,15 @@ public abstract class ThreadItemAdapter private final NestedTreeList items = new NestedTreeList<>(); private final Map animatingItems = new HashMap<>(); + private final ThreadItemListener listener; + private final LinearLayoutManager layoutManager; + // highlight not dependant on time private I replyItem; // temporary highlight private I addedItem; - private final ThreadItemListener listener; - private final LinearLayoutManager layoutManager; + private volatile int revision = 0; public ThreadItemAdapter(ThreadItemListener listener, LinearLayoutManager layoutManager) { @@ -290,6 +292,29 @@ public abstract class ThreadItemAdapter animatingItems.remove(item); } + /** + * Returns the adapter's revision counter. This method should be called on + * any thread before starting an asynchronous load that could overwrite + * other changes to the adapter, and called again on the UI thread before + * applying the changes from the asynchronous load. If the revision has + * changed between the two calls, the asynchronous load should be restarted + * without applying its changes. Otherwise {@link #incrementRevision()} + * should be called before applying the changes. + */ + public int getRevision() { + return revision; + } + + /** + * Increments the adapter's revision counter. This method should be called + * on the UI thread before applying any changes to the adapter that could + * be overwritten by an asynchronous load. + */ + @UiThread + public void incrementRevision() { + revision++; + } + protected interface ThreadItemListener { void onItemVisible(I item); diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java index 5ae9b5c6f..6a1ec4883 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java @@ -29,6 +29,7 @@ import org.briarproject.api.sync.MessageId; import org.briarproject.util.StringUtils; import java.util.Collection; +import java.util.logging.Logger; import static android.support.design.widget.Snackbar.make; import static android.view.View.GONE; @@ -42,6 +43,9 @@ public abstract class ThreadListActivity, DbException>( - this) { + new UiResultExceptionHandler, DbException>(this) { @Override public void onResultUi(Collection items) { - if (items.isEmpty()) { - list.showData(); + if (revision == adapter.getRevision()) { + adapter.incrementRevision(); + if (items.isEmpty()) { + list.showData(); + } else { + adapter.setItems(items); + list.showData(); + if (replyId != null) + adapter.setReplyItemById(replyId); + } } else { - adapter.setItems(items); - list.showData(); - if (replyId != null) - adapter.setReplyItemById(replyId); + LOG.info("Concurrent update, reloading"); + loadItems(); } } @@ -271,6 +281,7 @@ public abstract class ThreadListActivity protected final Context ctx; protected final SortedList items; + private volatile int revision = 0; + public BriarAdapter(Context ctx, Class c) { this.ctx = ctx; this.items = new SortedList<>(c, new SortedList.Callback() { @@ -110,4 +113,26 @@ public abstract class BriarAdapter return items.size() == 0; } + /** + * Returns the adapter's revision counter. This method should be called on + * any thread before starting an asynchronous load that could overwrite + * other changes to the adapter, and called again on the UI thread before + * applying the changes from the asynchronous load. If the revision has + * changed between the two calls, the asynchronous load should be restarted + * without applying its changes. Otherwise {@link #incrementRevision()} + * should be called before applying the changes. + */ + public int getRevision() { + return revision; + } + + /** + * Increments the adapter's revision counter. This method should be called + * on the UI thread before applying any changes to the adapter that could + * be overwritten by an asynchronous load. + */ + @UiThread + public void incrementRevision() { + revision++; + } } From e8ebdc2884484152ed8a5a088ff90d36598f8b8d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 20 Oct 2016 11:24:35 +0100 Subject: [PATCH 3/5] Don't finish nav drawer fragments on error. --- .../src/org/briarproject/android/blogs/FeedFragment.java | 3 --- .../android/privategroup/list/GroupListFragment.java | 2 -- 2 files changed, 5 deletions(-) diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java index cf9784160..9545f34ff 100644 --- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java @@ -125,7 +125,6 @@ public class FeedFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - finish(); } }); } @@ -151,7 +150,6 @@ public class FeedFragment extends BaseFragment implements @Override public void onExceptionUi(DbException e) { // TODO: Decide how to handle errors in the UI - finish(); } }); list.startPeriodicUpdate(); @@ -214,7 +212,6 @@ public class FeedFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO: Decide how to handle errors in the UI - finish(); } } ); diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java index 551c8f30b..4489dd6bf 100644 --- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java +++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java @@ -114,7 +114,6 @@ public class GroupListFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO handle error - finish(); } }); } @@ -169,7 +168,6 @@ public class GroupListFragment extends BaseFragment implements @Override public void onExceptionUi(DbException exception) { // TODO handle this error - finish(); } }); } From 9bb16b424fe4b583f85e1405fb2ad59fbca04adb Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 20 Oct 2016 12:38:13 +0100 Subject: [PATCH 4/5] Moved revision counter methods into their own interface. --- .../android/threaded/ThreadItemAdapter.java | 21 ++++----------- .../android/util/BriarAdapter.java | 18 +++---------- .../android/util/VersionedAdapter.java | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 31 deletions(-) create mode 100644 briar-android/src/org/briarproject/android/util/VersionedAdapter.java diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java index 034b6924f..c8ab7f2ba 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java @@ -6,6 +6,7 @@ import android.support.annotation.UiThread; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import org.briarproject.android.util.VersionedAdapter; import org.briarproject.api.sync.MessageId; import java.util.ArrayList; @@ -16,9 +17,9 @@ import java.util.Map; import static android.support.v7.widget.RecyclerView.NO_POSITION; -@UiThread public abstract class ThreadItemAdapter - extends RecyclerView.Adapter> { + extends RecyclerView.Adapter> + implements VersionedAdapter { static final int UNDEFINED = -1; @@ -292,25 +293,13 @@ public abstract class ThreadItemAdapter animatingItems.remove(item); } - /** - * Returns the adapter's revision counter. This method should be called on - * any thread before starting an asynchronous load that could overwrite - * other changes to the adapter, and called again on the UI thread before - * applying the changes from the asynchronous load. If the revision has - * changed between the two calls, the asynchronous load should be restarted - * without applying its changes. Otherwise {@link #incrementRevision()} - * should be called before applying the changes. - */ + @Override public int getRevision() { return revision; } - /** - * Increments the adapter's revision counter. This method should be called - * on the UI thread before applying any changes to the adapter that could - * be overwritten by an asynchronous load. - */ @UiThread + @Override public void incrementRevision() { revision++; } diff --git a/briar-android/src/org/briarproject/android/util/BriarAdapter.java b/briar-android/src/org/briarproject/android/util/BriarAdapter.java index eb566b8bd..091dcc8a1 100644 --- a/briar-android/src/org/briarproject/android/util/BriarAdapter.java +++ b/briar-android/src/org/briarproject/android/util/BriarAdapter.java @@ -12,7 +12,7 @@ import java.util.Collection; import static android.support.v7.util.SortedList.INVALID_POSITION; public abstract class BriarAdapter - extends Adapter { + extends Adapter implements VersionedAdapter { protected final Context ctx; protected final SortedList items; @@ -113,25 +113,13 @@ public abstract class BriarAdapter return items.size() == 0; } - /** - * Returns the adapter's revision counter. This method should be called on - * any thread before starting an asynchronous load that could overwrite - * other changes to the adapter, and called again on the UI thread before - * applying the changes from the asynchronous load. If the revision has - * changed between the two calls, the asynchronous load should be restarted - * without applying its changes. Otherwise {@link #incrementRevision()} - * should be called before applying the changes. - */ + @Override public int getRevision() { return revision; } - /** - * Increments the adapter's revision counter. This method should be called - * on the UI thread before applying any changes to the adapter that could - * be overwritten by an asynchronous load. - */ @UiThread + @Override public void incrementRevision() { revision++; } diff --git a/briar-android/src/org/briarproject/android/util/VersionedAdapter.java b/briar-android/src/org/briarproject/android/util/VersionedAdapter.java new file mode 100644 index 000000000..26df190cd --- /dev/null +++ b/briar-android/src/org/briarproject/android/util/VersionedAdapter.java @@ -0,0 +1,26 @@ +package org.briarproject.android.util; + +import android.support.annotation.UiThread; + +public interface VersionedAdapter { + + /** + * Returns the adapter's revision counter. This method should be called on + * any thread before starting an asynchronous load that could overwrite + * other changes to the adapter, and called again on the UI thread before + * applying the changes from the asynchronous load. If the revision has + * changed between the two calls, the asynchronous load should be restarted + * without applying its changes. Otherwise {@link #incrementRevision()} + * should be called before applying the changes. + */ + int getRevision(); + + /** + * Increments the adapter's revision counter. This method should be called + * on the UI thread before applying any changes to the adapter that could + * be overwritten by an asynchronous load. + */ + @UiThread + void incrementRevision(); + +} From c4716ca45726e28bd0b4ef9fca660979c9322ecc Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 20 Oct 2016 14:21:10 +0100 Subject: [PATCH 5/5] BlogFragment doesn't need to use adapter revisions. All changes to the adapter are cumulative. --- .../android/blogs/BlogFragment.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java index d70bdb14e..eb6552091 100644 --- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java +++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java @@ -32,7 +32,6 @@ import org.briarproject.api.identity.Author; import org.briarproject.api.sync.GroupId; import java.util.Collection; -import java.util.logging.Logger; import javax.inject.Inject; @@ -52,7 +51,6 @@ public class BlogFragment extends BaseFragment implements OnBlogPostAddedListener { public final static String TAG = BlogFragment.class.getName(); - private static final Logger LOG = Logger.getLogger(TAG); @Inject BlogController blogController; @@ -209,7 +207,6 @@ public class BlogFragment extends BaseFragment implements listener) { @Override public void onResultUi(BlogPostItem post) { - adapter.incrementRevision(); adapter.add(post); if (local) { list.scrollToPosition(0); @@ -231,23 +228,16 @@ public class BlogFragment extends BaseFragment implements } void loadBlogPosts(final boolean reload) { - final int revision = adapter.getRevision(); blogController.loadBlogPosts( new UiResultExceptionHandler, DbException>( listener) { @Override public void onResultUi(Collection posts) { - if (revision == adapter.getRevision()) { - adapter.incrementRevision(); - if (posts.isEmpty()) { - list.showData(); - } else { - adapter.addAll(posts); - if (reload) list.scrollToPosition(0); - } + if (posts.isEmpty()) { + list.showData(); } else { - LOG.info("Concurrent update, reloading"); - loadBlogPosts(reload); + adapter.addAll(posts); + if (reload) list.scrollToPosition(0); } }