mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Merge branch '705-adapter-revisions' into 'master'
Fix race conditions when updating UI from events (again) This is my second attempt at fixing race conditions caused by updating the UI from events while background tasks are loading data from the DB. Unlike my first attempt, this one is pretty simple and doesn't require too much reasoning about possible races. The first commit fixes a few list loading bugs I found while working on this problem, and moves the lifecycle callbacks from resume/pause to start/stop, closing #609. The second commit contains the fix for #705, which works as follows: * Each BriarAdapter has a revision counter * Before making a change to the adapter that could be overwritten by a background task, increment the revision * Before starting a background task that could overwrite other changes, get the current revision * Before applying changes from a background task that could overwrite other changes, check whether the revision has changed * If the revision has changed, restart the background task * Otherwise apply the changes Closes #609. #705 remains open because the PagerAdapters for blogs need to be updated. See merge request !356
This commit is contained in:
@@ -12,7 +12,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
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 android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||||
import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
|
import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
|
||||||
|
|
||||||
@@ -62,18 +61,18 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
for (ActivityLifecycleController alc : lifecycleControllers) {
|
for (ActivityLifecycleController alc : lifecycleControllers) {
|
||||||
alc.onActivityResume();
|
alc.onActivityStart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
for (ActivityLifecycleController alc : lifecycleControllers) {
|
for (ActivityLifecycleController alc : lifecycleControllers) {
|
||||||
alc.onActivityPause();
|
alc.onActivityStop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
Logger.getLogger(BriarActivity.class.getName());
|
Logger.getLogger(BriarActivity.class.getName());
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected BriarController briarController;
|
BriarController briarController;
|
||||||
// TODO remove this when the deprecated method runOnDbThread is removed
|
|
||||||
|
@Deprecated
|
||||||
@Inject
|
@Inject
|
||||||
protected DbController dbController;
|
DbController dbController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int request, int result, Intent data) {
|
protected void onActivityResult(int request, int result, Intent data) {
|
||||||
@@ -49,8 +50,8 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
if (!briarController.hasEncryptionKey() && !isFinishing()) {
|
if (!briarController.hasEncryptionKey() && !isFinishing()) {
|
||||||
Intent i = new Intent(this, PasswordActivity.class);
|
Intent i = new Intent(this, PasswordActivity.class);
|
||||||
i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
|
i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
updateTransports();
|
updateTransports();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import org.briarproject.api.blogs.BlogManager;
|
|||||||
import org.briarproject.api.blogs.BlogPostHeader;
|
import org.briarproject.api.blogs.BlogPostHeader;
|
||||||
import org.briarproject.api.db.DatabaseExecutor;
|
import org.briarproject.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.api.db.DbException;
|
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.EventBus;
|
||||||
import org.briarproject.api.event.EventListener;
|
import org.briarproject.api.event.EventListener;
|
||||||
import org.briarproject.api.identity.IdentityManager;
|
import org.briarproject.api.identity.IdentityManager;
|
||||||
@@ -47,7 +45,7 @@ abstract class BaseControllerImpl extends DbControllerImpl
|
|||||||
private final Map<MessageId, BlogPostHeader> headerCache =
|
private final Map<MessageId, BlogPostHeader> headerCache =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
protected volatile OnBlogPostAddedListener listener;
|
private volatile OnBlogPostAddedListener listener;
|
||||||
|
|
||||||
BaseControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
BaseControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager, EventBus eventBus,
|
LifecycleManager lifecycleManager, EventBus eventBus,
|
||||||
@@ -63,9 +61,7 @@ abstract class BaseControllerImpl extends DbControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
@CallSuper
|
@CallSuper
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (listener == null)
|
if (listener == null) throw new IllegalStateException();
|
||||||
throw new IllegalStateException(
|
|
||||||
"OnBlogPostAddedListener needs to be attached");
|
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,26 +71,30 @@ abstract class BaseControllerImpl extends DbControllerImpl
|
|||||||
eventBus.removeListener(this);
|
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
|
@Override
|
||||||
public void setOnBlogPostAddedListener(OnBlogPostAddedListener listener) {
|
public void setOnBlogPostAddedListener(OnBlogPostAddedListener listener) {
|
||||||
this.listener = 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
|
@Override
|
||||||
public void loadBlogPosts(final GroupId groupId,
|
public void loadBlogPosts(final GroupId groupId,
|
||||||
final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
|
final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
public class BlogControllerImpl extends BaseControllerImpl
|
public class BlogControllerImpl extends BaseControllerImpl
|
||||||
@@ -50,15 +51,15 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResume() {
|
public void onActivityStart() {
|
||||||
super.onStart(); // TODO: Should be called when activity starts. #609
|
super.onStart();
|
||||||
notificationManager.blockNotification(groupId);
|
notificationManager.blockNotification(groupId);
|
||||||
notificationManager.clearBlogPostNotification(groupId);
|
notificationManager.clearBlogPostNotification(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityPause() {
|
public void onActivityStop() {
|
||||||
super.onStop(); // TODO: Should be called when activity stops. #609
|
super.onStop();
|
||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,20 +76,16 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (groupId == null) throw new IllegalStateException();
|
if (groupId == null) throw new IllegalStateException();
|
||||||
if (e instanceof BlogPostAddedEvent) {
|
if (e instanceof BlogPostAddedEvent) {
|
||||||
BlogPostAddedEvent s = (BlogPostAddedEvent) e;
|
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
|
||||||
if (s.getGroupId().equals(groupId)) {
|
if (b.getGroupId().equals(groupId)) {
|
||||||
super.eventOccurred(e);
|
LOG.info("Blog post added");
|
||||||
|
onBlogPostAdded(b.getHeader(), b.isLocal());
|
||||||
}
|
}
|
||||||
} else if (e instanceof GroupRemovedEvent) {
|
} else if (e instanceof GroupRemovedEvent) {
|
||||||
GroupRemovedEvent s = (GroupRemovedEvent) e;
|
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||||
if (s.getGroup().getId().equals(groupId)) {
|
if (g.getGroup().getId().equals(groupId)) {
|
||||||
LOG.info("Blog removed");
|
LOG.info("Blog removed");
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
onBlogRemoved();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
listener.onBlogRemoved();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,11 +112,15 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
LocalAuthor a = identityManager.getLocalAuthor();
|
LocalAuthor a = identityManager.getLocalAuthor();
|
||||||
Blog b = blogManager.getBlog(groupId);
|
Blog b = blogManager.getBlog(groupId);
|
||||||
boolean ours = a.getId().equals(b.getAuthor().getId());
|
boolean ours = a.getId().equals(b.getAuthor().getId());
|
||||||
boolean removable = blogManager.canBeRemoved(groupId);
|
boolean removable = blogManager.canBeRemoved(groupId);
|
||||||
BlogItem blog = new BlogItem(b, ours, removable);
|
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);
|
handler.onResult(blog);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
@@ -138,8 +139,12 @@ public class BlogControllerImpl extends BaseControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
Blog b = blogManager.getBlog(groupId);
|
Blog b = blogManager.getBlog(groupId);
|
||||||
blogManager.removeBlog(b);
|
blogManager.removeBlog(b);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Removing blog took " + duration + " ms");
|
||||||
handler.onResult(null);
|
handler.onResult(null);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
|
|||||||
@@ -123,18 +123,13 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
loadBlog();
|
loadBlog();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
loadBlogPosts(false);
|
loadBlogPosts(false);
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,9 +210,11 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
if (local) {
|
if (local) {
|
||||||
list.scrollToPosition(0);
|
list.scrollToPosition(0);
|
||||||
displaySnackbar(R.string.blogs_blog_post_created, false);
|
displaySnackbar(R.string.blogs_blog_post_created,
|
||||||
|
false);
|
||||||
} else {
|
} 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) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (posts.size() > 0) {
|
if (posts.isEmpty()) {
|
||||||
|
list.showData();
|
||||||
|
} else {
|
||||||
adapter.addAll(posts);
|
adapter.addAll(posts);
|
||||||
if (reload) list.scrollToPosition(0);
|
if (reload) list.scrollToPosition(0);
|
||||||
} else {
|
|
||||||
list.showData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.android.blogs;
|
package org.briarproject.android.blogs;
|
||||||
|
|
||||||
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
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.Blog;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
|
||||||
@@ -12,6 +11,6 @@ public interface FeedController extends BaseController {
|
|||||||
void loadBlogPosts(
|
void loadBlogPosts(
|
||||||
ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler);
|
ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler);
|
||||||
|
|
||||||
void loadPersonalBlog(ResultHandler<Blog> resultHandler);
|
void loadPersonalBlog(ResultExceptionHandler<Blog, DbException> handler);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ package org.briarproject.android.blogs;
|
|||||||
|
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
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.Blog;
|
||||||
import org.briarproject.api.blogs.BlogManager;
|
import org.briarproject.api.blogs.BlogManager;
|
||||||
import org.briarproject.api.db.DatabaseExecutor;
|
import org.briarproject.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.db.NoSuchGroupException;
|
import org.briarproject.api.db.NoSuchGroupException;
|
||||||
import org.briarproject.api.db.NoSuchMessageException;
|
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.EventBus;
|
||||||
|
import org.briarproject.api.event.GroupRemovedEvent;
|
||||||
import org.briarproject.api.identity.Author;
|
import org.briarproject.api.identity.Author;
|
||||||
import org.briarproject.api.identity.IdentityManager;
|
import org.briarproject.api.identity.IdentityManager;
|
||||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||||
@@ -52,15 +54,28 @@ public class FeedControllerImpl extends BaseControllerImpl
|
|||||||
notificationManager.unblockAllBlogPostNotifications();
|
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
|
@Override
|
||||||
public void loadBlogPosts(
|
public void loadBlogPosts(
|
||||||
final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
|
final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
|
||||||
LOG.info("Loading all blog posts...");
|
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// load blog posts
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Collection<BlogPostItem> posts = new ArrayList<>();
|
Collection<BlogPostItem> posts = new ArrayList<>();
|
||||||
for (Blog b : blogManager.getBlogs()) {
|
for (Blog b : blogManager.getBlogs()) {
|
||||||
@@ -85,24 +100,23 @@ public class FeedControllerImpl extends BaseControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadPersonalBlog(final ResultHandler<Blog> resultHandler) {
|
public void loadPersonalBlog(
|
||||||
LOG.info("Loading personal blog...");
|
final ResultExceptionHandler<Blog, DbException> handler) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// load blog posts
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Author a = identityManager.getLocalAuthor();
|
Author a = identityManager.getLocalAuthor();
|
||||||
Blog b = blogManager.getPersonalBlog(a);
|
Blog b = blogManager.getPersonalBlog(a);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading pers. blog took " + duration + " ms");
|
LOG.info("Loading blog took " + duration + " ms");
|
||||||
resultHandler.onResult(b);
|
handler.onResult(b);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
resultHandler.onResult(null);
|
handler.onException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.briarproject.android.ActivityComponent;
|
|||||||
import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener;
|
import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener;
|
||||||
import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
|
import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
|
||||||
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.android.controller.handler.UiResultHandler;
|
|
||||||
import org.briarproject.android.fragment.BaseFragment;
|
import org.briarproject.android.fragment.BaseFragment;
|
||||||
import org.briarproject.android.view.BriarRecyclerView;
|
import org.briarproject.android.view.BriarRecyclerView;
|
||||||
import org.briarproject.api.blogs.Blog;
|
import org.briarproject.api.blogs.Blog;
|
||||||
@@ -28,6 +27,7 @@ import org.briarproject.api.blogs.BlogPostHeader;
|
|||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
OnBlogPostClickListener, OnBlogPostAddedListener {
|
OnBlogPostClickListener, OnBlogPostAddedListener {
|
||||||
|
|
||||||
public final static String TAG = FeedFragment.class.getName();
|
public final static String TAG = FeedFragment.class.getName();
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
FeedController feedController;
|
FeedController feedController;
|
||||||
@@ -99,40 +100,61 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
feedController.onStart();
|
feedController.onStart();
|
||||||
feedController.loadPersonalBlog(
|
loadPersonalBlog();
|
||||||
new UiResultHandler<Blog>(listener) {
|
loadBlogPosts(false);
|
||||||
@Override
|
|
||||||
public void onResultUi(Blog b) {
|
|
||||||
personalBlog = b;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
feedController.loadBlogPosts(
|
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
|
||||||
listener) {
|
|
||||||
@Override
|
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
|
||||||
if (posts.isEmpty()) {
|
|
||||||
list.showData();
|
|
||||||
} else {
|
|
||||||
adapter.addAll(posts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onExceptionUi(DbException exception) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
});
|
|
||||||
list.startPeriodicUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
feedController.onStop();
|
feedController.onStop();
|
||||||
|
adapter.clear();
|
||||||
|
list.showProgressBar();
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
// TODO save list position in database/preferences?
|
// TODO save list position in database/preferences?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadPersonalBlog() {
|
||||||
|
feedController.loadPersonalBlog(
|
||||||
|
new UiResultExceptionHandler<Blog, DbException>(listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Blog b) {
|
||||||
|
personalBlog = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
// TODO: Decide how to handle errors in the UI
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadBlogPosts(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
|
feedController.loadBlogPosts(
|
||||||
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
|
listener) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
|
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
|
||||||
|
public void onExceptionUi(DbException e) {
|
||||||
|
// TODO: Decide how to handle errors in the UI
|
||||||
|
}
|
||||||
|
});
|
||||||
|
list.startPeriodicUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.blogs_feed_actions, menu);
|
inflater.inflate(R.menu.blogs_feed_actions, menu);
|
||||||
@@ -178,6 +200,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
if (local) {
|
if (local) {
|
||||||
showSnackBar(R.string.blogs_blog_post_created);
|
showSnackBar(R.string.blogs_blog_post_created);
|
||||||
@@ -185,6 +208,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
showSnackBar(R.string.blogs_blog_post_received);
|
showSnackBar(R.string.blogs_blog_post_received);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO: Decide how to handle errors in the UI
|
// TODO: Decide how to handle errors in the UI
|
||||||
@@ -234,6 +258,6 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlogRemoved() {
|
public void onBlogRemoved() {
|
||||||
finish();
|
loadBlogPosts(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
|
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private RssFeedAdapter adapter;
|
private RssFeedAdapter adapter;
|
||||||
|
private GroupId groupId;
|
||||||
// Fields that are accessed from background threads must be volatile
|
|
||||||
private volatile GroupId groupId = null;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@@ -65,11 +63,18 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
loadFeeds();
|
loadFeeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
adapter.clear();
|
||||||
|
list.showProgressBar();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
@@ -120,27 +125,43 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadFeeds() {
|
private void loadFeeds() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
addFeeds(feedManager.getFeeds());
|
displayFeeds(revision, feedManager.getFeeds());
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
list.setEmptyText(R.string.blogs_rss_feeds_manage_error);
|
onLoadError();
|
||||||
list.showData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFeeds(final List<Feed> feeds) {
|
private void displayFeeds(final int revision, final List<Feed> feeds) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (feeds.size() == 0) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(feeds);
|
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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -149,6 +170,7 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.remove(feed);
|
adapter.remove(feed);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -94,15 +94,15 @@ public class WriteBlogPostActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStart() {
|
||||||
super.onPause();
|
super.onStart();
|
||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.blockNotification(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStop() {
|
||||||
super.onResume();
|
super.onStop();
|
||||||
notificationManager.blockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.briarproject.R;
|
|||||||
import org.briarproject.android.util.BriarAdapter;
|
import org.briarproject.android.util.BriarAdapter;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.identity.Author;
|
import org.briarproject.api.identity.Author;
|
||||||
import org.briarproject.api.sync.GroupId;
|
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
@@ -90,17 +89,6 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
|
|||||||
return INVALID_POSITION; // Not found
|
return INVALID_POSITION; // Not found
|
||||||
}
|
}
|
||||||
|
|
||||||
int findItemPosition(GroupId g) {
|
|
||||||
int count = getItemCount();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
ContactListItem item = getItemAt(i);
|
|
||||||
if (item != null && item.getGroupId().equals(g)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return INVALID_POSITION; // Not found
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BaseContactHolder extends RecyclerView.ViewHolder {
|
public static class BaseContactHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
public final ViewGroup layout;
|
public final ViewGroup layout;
|
||||||
|
|||||||
@@ -170,8 +170,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
notificationManager.blockAllContactNotifications();
|
notificationManager.blockAllContactNotifications();
|
||||||
notificationManager.clearAllContactNotifications();
|
notificationManager.clearAllContactNotifications();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
@@ -180,8 +180,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
notificationManager.unblockAllContactNotifications();
|
notificationManager.unblockAllContactNotifications();
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
@@ -190,6 +190,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadContacts() {
|
private void loadContacts() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
listener.runOnDbThread(new Runnable() {
|
listener.runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -213,10 +214,10 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayContacts(contacts);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
|
displayContacts(revision, contacts);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -225,12 +226,19 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayContacts(final List<ContactListItem> contacts) {
|
private void displayContacts(final int revision,
|
||||||
|
final List<ContactListItem> contacts) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (contacts.size() == 0) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(contacts);
|
adapter.incrementRevision();
|
||||||
|
if (contacts.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(contacts);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadContacts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -238,40 +246,45 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactStatusChangedEvent) {
|
if (e instanceof ContactStatusChangedEvent) {
|
||||||
LOG.info("Contact Status changed, reloading");
|
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||||
// is also broadcast when contact was added
|
if (c.isActive()) {
|
||||||
loadContacts();
|
LOG.info("Contact activated, reloading");
|
||||||
|
loadContacts();
|
||||||
|
} else {
|
||||||
|
LOG.info("Contact deactivated, removing item");
|
||||||
|
removeItem(c.getContactId());
|
||||||
|
}
|
||||||
} else if (e instanceof ContactConnectedEvent) {
|
} else if (e instanceof ContactConnectedEvent) {
|
||||||
setConnected(((ContactConnectedEvent) e).getContactId(), true);
|
setConnected(((ContactConnectedEvent) e).getContactId(), true);
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
|
setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
|
||||||
} else if (e instanceof ContactRemovedEvent) {
|
} else if (e instanceof ContactRemovedEvent) {
|
||||||
LOG.info("Contact removed");
|
LOG.info("Contact removed, removing item");
|
||||||
removeItem(((ContactRemovedEvent) e).getContactId());
|
removeItem(((ContactRemovedEvent) e).getContactId());
|
||||||
} else if (e instanceof PrivateMessageReceivedEvent) {
|
} else if (e instanceof PrivateMessageReceivedEvent) {
|
||||||
LOG.info("Message received, update contact");
|
LOG.info("Private message received, updating item");
|
||||||
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
||||||
PrivateMessageHeader h = p.getMessageHeader();
|
PrivateMessageHeader h = p.getMessageHeader();
|
||||||
updateItem(p.getGroupId(), ConversationItem.from(h));
|
updateItem(p.getContactId(), ConversationItem.from(h));
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
||||||
LOG.info("Introduction Request received, update contact");
|
LOG.info("Introduction request received, updating item");
|
||||||
IntroductionRequestReceivedEvent m =
|
IntroductionRequestReceivedEvent m =
|
||||||
(IntroductionRequestReceivedEvent) e;
|
(IntroductionRequestReceivedEvent) e;
|
||||||
IntroductionRequest ir = m.getIntroductionRequest();
|
IntroductionRequest ir = m.getIntroductionRequest();
|
||||||
updateItem(m.getContactId(), ConversationItem.from(ir));
|
updateItem(m.getContactId(), ConversationItem.from(ir));
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
||||||
LOG.info("Introduction Response received, update contact");
|
LOG.info("Introduction response received, updating item");
|
||||||
IntroductionResponseReceivedEvent m =
|
IntroductionResponseReceivedEvent m =
|
||||||
(IntroductionResponseReceivedEvent) e;
|
(IntroductionResponseReceivedEvent) e;
|
||||||
IntroductionResponse ir = m.getIntroductionResponse();
|
IntroductionResponse ir = m.getIntroductionResponse();
|
||||||
updateItem(m.getContactId(), ConversationItem.from(ir));
|
updateItem(m.getContactId(), ConversationItem.from(ir));
|
||||||
} else if (e instanceof InvitationRequestReceivedEvent) {
|
} else if (e instanceof InvitationRequestReceivedEvent) {
|
||||||
LOG.info("Invitation Request received, update contact");
|
LOG.info("Invitation request received, updating item");
|
||||||
InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
|
InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
|
||||||
InvitationRequest ir = m.getRequest();
|
InvitationRequest ir = m.getRequest();
|
||||||
updateItem(m.getContactId(), ConversationItem.from(ir));
|
updateItem(m.getContactId(), ConversationItem.from(ir));
|
||||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
} else if (e instanceof InvitationResponseReceivedEvent) {
|
||||||
LOG.info("Invitation Response received, update contact");
|
LOG.info("Invitation response received, updating item");
|
||||||
InvitationResponseReceivedEvent m =
|
InvitationResponseReceivedEvent m =
|
||||||
(InvitationResponseReceivedEvent) e;
|
(InvitationResponseReceivedEvent) e;
|
||||||
InvitationResponse ir = m.getResponse();
|
InvitationResponse ir = m.getResponse();
|
||||||
@@ -283,6 +296,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -293,24 +307,11 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateItem(final GroupId g, final ConversationItem m) {
|
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int position = adapter.findItemPosition(g);
|
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
|
||||||
if (item != null) {
|
|
||||||
item.addMessage(m);
|
|
||||||
adapter.updateItemAt(position, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeItem(final ContactId c) {
|
private void removeItem(final ContactId c) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
@@ -322,6 +323,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import org.briarproject.android.view.TextInputView;
|
|||||||
import org.briarproject.android.view.TextInputView.TextInputListener;
|
import org.briarproject.android.view.TextInputView.TextInputListener;
|
||||||
import org.briarproject.api.FormatException;
|
import org.briarproject.api.FormatException;
|
||||||
import org.briarproject.api.blogs.BlogSharingManager;
|
import org.briarproject.api.blogs.BlogSharingManager;
|
||||||
import org.briarproject.api.clients.BaseMessageHeader;
|
|
||||||
import org.briarproject.api.clients.SessionId;
|
import org.briarproject.api.clients.SessionId;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
@@ -42,7 +41,6 @@ import org.briarproject.api.contact.ContactManager;
|
|||||||
import org.briarproject.api.crypto.CryptoExecutor;
|
import org.briarproject.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
import org.briarproject.api.db.NoSuchContactException;
|
import org.briarproject.api.db.NoSuchContactException;
|
||||||
import org.briarproject.api.db.NoSuchMessageException;
|
|
||||||
import org.briarproject.api.event.ContactConnectedEvent;
|
import org.briarproject.api.event.ContactConnectedEvent;
|
||||||
import org.briarproject.api.event.ContactDisconnectedEvent;
|
import org.briarproject.api.event.ContactDisconnectedEvent;
|
||||||
import org.briarproject.api.event.ContactRemovedEvent;
|
import org.briarproject.api.event.ContactRemovedEvent;
|
||||||
@@ -150,7 +148,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
private volatile ContactId contactId = null;
|
private volatile ContactId contactId = null;
|
||||||
private volatile String contactName = null;
|
private volatile String contactName = null;
|
||||||
private volatile byte[] contactIdenticonKey = null;
|
private volatile byte[] contactIdenticonKey = null;
|
||||||
private volatile boolean connected = false;
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
@@ -214,18 +211,19 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
notificationManager.blockNotification(groupId);
|
notificationManager.blockNotification(groupId);
|
||||||
notificationManager.clearPrivateMessageNotification(groupId);
|
notificationManager.clearPrivateMessageNotification(groupId);
|
||||||
loadData();
|
loadContactDetails();
|
||||||
|
loadMessages();
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
@@ -277,7 +275,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData() {
|
private void loadContactDetails() {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -291,13 +289,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
contactIdenticonKey =
|
contactIdenticonKey =
|
||||||
contact.getAuthor().getId().getBytes();
|
contact.getAuthor().getId().getBytes();
|
||||||
}
|
}
|
||||||
connected = connectionRegistry.isConnected(contactId);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading contact took " + duration + " ms");
|
LOG.info("Loading contact took " + duration + " ms");
|
||||||
displayContactDetails();
|
displayContactDetails();
|
||||||
// Load the messages here to make sure we have a contactId
|
|
||||||
loadMessages();
|
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -316,7 +311,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
new IdenticonDrawable(contactIdenticonKey));
|
new IdenticonDrawable(contactIdenticonKey));
|
||||||
toolbarTitle.setText(contactName);
|
toolbarTitle.setText(contactName);
|
||||||
|
|
||||||
if (connected) {
|
if (connectionRegistry.isConnected(contactId)) {
|
||||||
toolbarStatus.setImageDrawable(ContextCompat
|
toolbarStatus.setImageDrawable(ContextCompat
|
||||||
.getDrawable(ConversationActivity.this,
|
.getDrawable(ConversationActivity.this,
|
||||||
R.drawable.contact_online));
|
R.drawable.contact_online));
|
||||||
@@ -335,6 +330,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessages() {
|
private void loadMessages() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -359,8 +355,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
invitations.addAll(blogInvitations);
|
invitations.addAll(blogInvitations);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading headers took " + duration + " ms");
|
LOG.info("Loading messages took " + duration + " ms");
|
||||||
displayMessages(headers, introductions, invitations);
|
displayMessages(revision, headers, introductions,
|
||||||
|
invitations);
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -371,59 +368,66 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayMessages(final Collection<PrivateMessageHeader> headers,
|
private void displayMessages(final int revision,
|
||||||
|
final Collection<PrivateMessageHeader> headers,
|
||||||
final Collection<IntroductionMessage> introductions,
|
final Collection<IntroductionMessage> introductions,
|
||||||
final Collection<InvitationMessage> invitations) {
|
final Collection<InvitationMessage> invitations) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
textInputView.setSendButtonEnabled(true);
|
if (revision == adapter.getRevision()) {
|
||||||
if (headers.isEmpty() && introductions.isEmpty() &&
|
adapter.incrementRevision();
|
||||||
invitations.isEmpty()) {
|
textInputView.setSendButtonEnabled(true);
|
||||||
// we have no messages,
|
List<ConversationItem> items = createItems(headers,
|
||||||
// so let the list know to hide progress bar
|
introductions, invitations);
|
||||||
list.showData();
|
if (items.isEmpty()) list.showData();
|
||||||
} else {
|
else adapter.addAll(items);
|
||||||
List<ConversationItem> items = new ArrayList<>();
|
|
||||||
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 m : introductions) {
|
|
||||||
ConversationItem item;
|
|
||||||
if (m instanceof IntroductionRequest) {
|
|
||||||
item = ConversationItem
|
|
||||||
.from((IntroductionRequest) m);
|
|
||||||
} 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;
|
|
||||||
items.add(ConversationItem
|
|
||||||
.from(ConversationActivity.this,
|
|
||||||
contactName, r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adapter.addAll(items);
|
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ConversationItem> createItems(
|
||||||
|
Collection<PrivateMessageHeader> headers,
|
||||||
|
Collection<IntroductionMessage> introductions,
|
||||||
|
Collection<InvitationMessage> invitations) {
|
||||||
|
int size = headers.size() + introductions.size() + invitations.size();
|
||||||
|
List<ConversationItem> 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) {
|
private void loadMessageBody(final MessageId m) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -435,8 +439,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading body took " + duration + " ms");
|
LOG.info("Loading body took " + duration + " ms");
|
||||||
displayMessageBody(m, body);
|
displayMessageBody(m, body);
|
||||||
} catch (NoSuchMessageException e) {
|
|
||||||
// The item will be removed when we get the event
|
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -469,6 +471,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
@@ -496,9 +499,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for (Map.Entry<MessageId, GroupId> e : unread.entrySet())
|
for (Map.Entry<MessageId, GroupId> e : unread.entrySet()) {
|
||||||
messagingManager
|
messagingManager.setReadFlag(e.getValue(), e.getKey(),
|
||||||
.setReadFlag(e.getValue(), e.getKey(), true);
|
true);
|
||||||
|
}
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
@@ -525,7 +529,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
PrivateMessageHeader h = p.getMessageHeader();
|
PrivateMessageHeader h = p.getMessageHeader();
|
||||||
addConversationItem(ConversationItem.from(h));
|
addConversationItem(ConversationItem.from(h));
|
||||||
loadMessageBody(h.getId());
|
loadMessageBody(h.getId());
|
||||||
markMessageReadIfNew(h);
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof MessagesSentEvent) {
|
} else if (e instanceof MessagesSentEvent) {
|
||||||
MessagesSentEvent m = (MessagesSentEvent) e;
|
MessagesSentEvent m = (MessagesSentEvent) e;
|
||||||
@@ -543,14 +546,12 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact connected");
|
LOG.info("Contact connected");
|
||||||
connected = true;
|
|
||||||
displayContactDetails();
|
displayContactDetails();
|
||||||
}
|
}
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact disconnected");
|
LOG.info("Contact disconnected");
|
||||||
connected = false;
|
|
||||||
displayContactDetails();
|
displayContactDetails();
|
||||||
}
|
}
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
||||||
@@ -561,7 +562,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
IntroductionRequest ir = event.getIntroductionRequest();
|
IntroductionRequest ir = event.getIntroductionRequest();
|
||||||
ConversationItem item = new ConversationIntroductionInItem(ir);
|
ConversationItem item = new ConversationIntroductionInItem(ir);
|
||||||
addConversationItem(item);
|
addConversationItem(item);
|
||||||
markMessageReadIfNew(ir);
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
||||||
IntroductionResponseReceivedEvent event =
|
IntroductionResponseReceivedEvent event =
|
||||||
@@ -572,7 +572,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ConversationItem item =
|
ConversationItem item =
|
||||||
ConversationItem.from(this, contactName, ir);
|
ConversationItem.from(this, contactName, ir);
|
||||||
addConversationItem(item);
|
addConversationItem(item);
|
||||||
markMessageReadIfNew(ir);
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof InvitationRequestReceivedEvent) {
|
} else if (e instanceof InvitationRequestReceivedEvent) {
|
||||||
InvitationRequestReceivedEvent event =
|
InvitationRequestReceivedEvent event =
|
||||||
@@ -582,7 +581,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
InvitationRequest ir = event.getRequest();
|
InvitationRequest ir = event.getRequest();
|
||||||
ConversationItem item = ConversationItem.from(ir);
|
ConversationItem item = ConversationItem.from(ir);
|
||||||
addConversationItem(item);
|
addConversationItem(item);
|
||||||
markMessageReadIfNew(ir);
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
} else if (e instanceof InvitationResponseReceivedEvent) {
|
||||||
InvitationResponseReceivedEvent event =
|
InvitationResponseReceivedEvent event =
|
||||||
@@ -593,51 +591,16 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ConversationItem item =
|
ConversationItem item =
|
||||||
ConversationItem.from(this, contactName, ir);
|
ConversationItem.from(this, contactName, ir);
|
||||||
addConversationItem(item);
|
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<MessageId> messageIds,
|
private void markMessages(final Collection<MessageId> messageIds,
|
||||||
final boolean sent, final boolean seen) {
|
final boolean sent, final boolean seen) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
Set<MessageId> messages = new HashSet<>(messageIds);
|
Set<MessageId> messages = new HashSet<>(messageIds);
|
||||||
SparseArray<OutgoingItem> list = adapter.getOutgoingMessages();
|
SparseArray<OutgoingItem> list = adapter.getOutgoingMessages();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
@@ -654,7 +617,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendClick(String text) {
|
public void onSendClick(String text) {
|
||||||
markMessagesRead();
|
|
||||||
if (text.equals("")) return;
|
if (text.equals("")) return;
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
||||||
@@ -857,13 +819,11 @@ public class ConversationActivity extends BriarActivity
|
|||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
||||||
try {
|
try {
|
||||||
if (accept) {
|
if (accept) {
|
||||||
introductionManager
|
introductionManager.acceptIntroduction(contactId,
|
||||||
.acceptIntroduction(contactId, sessionId,
|
sessionId, timestamp);
|
||||||
timestamp);
|
|
||||||
} else {
|
} else {
|
||||||
introductionManager
|
introductionManager.declineIntroduction(contactId,
|
||||||
.declineIntroduction(contactId, sessionId,
|
sessionId, timestamp);
|
||||||
timestamp);
|
|
||||||
}
|
}
|
||||||
loadMessages();
|
loadMessages();
|
||||||
} catch (DbException | FormatException e) {
|
} catch (DbException | FormatException e) {
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ public interface ActivityLifecycleController {
|
|||||||
|
|
||||||
void onActivityCreate(Activity activity);
|
void onActivityCreate(Activity activity);
|
||||||
|
|
||||||
void onActivityResume();
|
void onActivityStart();
|
||||||
|
|
||||||
void onActivityPause();
|
void onActivityStop();
|
||||||
|
|
||||||
void onActivityDestroy();
|
void onActivityDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,18 +19,18 @@ public class BriarControllerImpl implements BriarController {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BriarControllerImpl.class.getName());
|
Logger.getLogger(BriarControllerImpl.class.getName());
|
||||||
|
|
||||||
@Inject
|
private final BriarServiceConnection serviceConnection;
|
||||||
BriarServiceConnection serviceConnection;
|
private final DatabaseConfig databaseConfig;
|
||||||
@Inject
|
private final Activity activity;
|
||||||
DatabaseConfig databaseConfig;
|
|
||||||
@Inject
|
|
||||||
Activity activity;
|
|
||||||
|
|
||||||
private boolean bound = false;
|
private boolean bound = false;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BriarControllerImpl() {
|
BriarControllerImpl(BriarServiceConnection serviceConnection,
|
||||||
|
DatabaseConfig databaseConfig, Activity activity) {
|
||||||
|
this.serviceConnection = serviceConnection;
|
||||||
|
this.databaseConfig = databaseConfig;
|
||||||
|
this.activity = activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -40,13 +40,11 @@ public class BriarControllerImpl implements BriarController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CallSuper
|
public void onActivityStart() {
|
||||||
public void onActivityResume() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CallSuper
|
public void onActivityStop() {
|
||||||
public void onActivityPause() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ public class NavDrawerControllerImpl extends DbControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResume() {
|
public void onActivityStart() {
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityPause() {
|
public void onActivityStop() {
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.android.forum;
|
package org.briarproject.android.forum;
|
||||||
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
@@ -98,9 +99,8 @@ public class ForumActivity extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
ActivityOptionsCompat options =
|
ActivityOptionsCompat options = makeCustomAnimation(this,
|
||||||
makeCustomAnimation(this, android.R.anim.slide_in_left,
|
android.R.anim.slide_in_left, android.R.anim.slide_out_right);
|
||||||
android.R.anim.slide_out_right);
|
|
||||||
// Handle presses on the action bar items
|
// Handle presses on the action bar items
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_forum_compose_post:
|
case R.id.action_forum_compose_post:
|
||||||
@@ -110,9 +110,8 @@ public class ForumActivity extends
|
|||||||
Intent i2 = new Intent(this, ShareForumActivity.class);
|
Intent i2 = new Intent(this, ShareForumActivity.class);
|
||||||
i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
i2.putExtra(GROUP_ID, groupId.getBytes());
|
i2.putExtra(GROUP_ID, groupId.getBytes());
|
||||||
ActivityCompat
|
ActivityCompat.startActivityForResult(this, i2,
|
||||||
.startActivityForResult(this, i2, REQUEST_FORUM_SHARED,
|
REQUEST_FORUM_SHARED, options.toBundle());
|
||||||
options.toBundle());
|
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_forum_sharing_status:
|
case R.id.action_forum_sharing_status:
|
||||||
Intent i3 = new Intent(this, SharingStatusForumActivity.class);
|
Intent i3 = new Intent(this, SharingStatusForumActivity.class);
|
||||||
@@ -146,17 +145,14 @@ public class ForumActivity extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showUnsubscribeDialog() {
|
private void showUnsubscribeDialog() {
|
||||||
DialogInterface.OnClickListener okListener =
|
OnClickListener okListener = new OnClickListener() {
|
||||||
new DialogInterface.OnClickListener() {
|
@Override
|
||||||
@Override
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
public void onClick(final DialogInterface dialog,
|
deleteNamedGroup();
|
||||||
int which) {
|
}
|
||||||
deleteNamedGroup();
|
};
|
||||||
}
|
AlertDialog.Builder builder = new AlertDialog.Builder(
|
||||||
};
|
ForumActivity.this, R.style.BriarDialogTheme);
|
||||||
AlertDialog.Builder builder =
|
|
||||||
new AlertDialog.Builder(ForumActivity.this,
|
|
||||||
R.style.BriarDialogTheme);
|
|
||||||
builder.setTitle(getString(R.string.dialog_title_leave_forum));
|
builder.setTitle(getString(R.string.dialog_title_leave_forum));
|
||||||
builder.setMessage(getString(R.string.dialog_message_leave_forum));
|
builder.setMessage(getString(R.string.dialog_message_leave_forum));
|
||||||
builder.setNegativeButton(R.string.dialog_button_leave, okListener);
|
builder.setNegativeButton(R.string.dialog_button_leave, okListener);
|
||||||
@@ -166,19 +162,15 @@ public class ForumActivity extends
|
|||||||
|
|
||||||
private void deleteNamedGroup() {
|
private void deleteNamedGroup() {
|
||||||
forumController.deleteNamedGroup(
|
forumController.deleteNamedGroup(
|
||||||
new UiResultExceptionHandler<Void, DbException>(
|
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||||
ForumActivity.this) {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Void v) {
|
public void onResultUi(Void v) {
|
||||||
Toast.makeText(ForumActivity.this,
|
Toast.makeText(ForumActivity.this,
|
||||||
R.string.forum_left_toast,
|
R.string.forum_left_toast, LENGTH_SHORT).show();
|
||||||
LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(
|
public void onExceptionUi(DbException exception) {
|
||||||
DbException exception) {
|
|
||||||
// TODO proper error handling
|
// TODO proper error handling
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class ForumControllerImpl
|
public class ForumControllerImpl extends
|
||||||
extends ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost>
|
ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost>
|
||||||
implements ForumController {
|
implements ForumController {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -49,8 +49,8 @@ public class ForumControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResume() {
|
public void onActivityStart() {
|
||||||
super.onActivityResume();
|
super.onActivityStart();
|
||||||
notificationManager.clearForumPostNotification(getGroupId());
|
notificationManager.clearForumPostNotification(getGroupId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ public class ForumControllerImpl
|
|||||||
super.eventOccurred(e);
|
super.eventOccurred(e);
|
||||||
|
|
||||||
if (e instanceof ForumPostReceivedEvent) {
|
if (e instanceof ForumPostReceivedEvent) {
|
||||||
final ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
|
ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
|
||||||
if (pe.getGroupId().equals(getGroupId())) {
|
if (pe.getGroupId().equals(getGroupId())) {
|
||||||
LOG.info("Forum post received, adding...");
|
LOG.info("Forum post received, adding...");
|
||||||
final ForumPostHeader fph = pe.getForumPostHeader();
|
final ForumPostHeader fph = pe.getForumPostHeader();
|
||||||
@@ -102,9 +102,8 @@ public class ForumControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
protected ForumPost createLocalMessage(String body, long timestamp,
|
protected ForumPost createLocalMessage(String body, long timestamp,
|
||||||
@Nullable MessageId parentId, LocalAuthor author) {
|
@Nullable MessageId parentId, LocalAuthor author) {
|
||||||
return forumManager
|
return forumManager.createLocalPost(getGroupId(), body, timestamp,
|
||||||
.createLocalPost(getGroupId(), body, timestamp, parentId,
|
parentId, author);
|
||||||
author);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -111,9 +111,8 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
|
|
||||||
notificationManager.blockAllForumPostNotifications();
|
notificationManager.blockAllForumPostNotifications();
|
||||||
notificationManager.clearAllForumPostNotifications();
|
notificationManager.clearAllForumPostNotifications();
|
||||||
loadForums();
|
loadForums();
|
||||||
@@ -122,9 +121,8 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
|
|
||||||
notificationManager.unblockAllForumPostNotifications();
|
notificationManager.unblockAllForumPostNotifications();
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
list.showProgressBar();
|
list.showProgressBar();
|
||||||
@@ -152,11 +150,11 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadForums() {
|
private void loadForums() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
listener.runOnDbThread(new Runnable() {
|
listener.runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// load forums
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Collection<ForumListItem> forums = new ArrayList<>();
|
Collection<ForumListItem> forums = new ArrayList<>();
|
||||||
for (Forum f : forumManager.getForums()) {
|
for (Forum f : forumManager.getForums()) {
|
||||||
@@ -168,10 +166,10 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayForums(forums);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
|
displayForums(revision, forums);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -180,12 +178,19 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayForums(final Collection<ForumListItem> forums) {
|
private void displayForums(final int revision,
|
||||||
|
final Collection<ForumListItem> forums) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (forums.size() > 0) adapter.addAll(forums);
|
if (revision == adapter.getRevision()) {
|
||||||
else list.showData();
|
adapter.incrementRevision();
|
||||||
|
if (forums.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(forums);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadForums();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -245,9 +250,10 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
}
|
}
|
||||||
} else if (e instanceof ForumPostReceivedEvent) {
|
} else if (e instanceof ForumPostReceivedEvent) {
|
||||||
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
||||||
LOG.info("Forum post added, updating...");
|
LOG.info("Forum post added, updating item");
|
||||||
updateItem(f.getGroupId(), f.getForumPostHeader());
|
updateItem(f.getGroupId(), f.getForumPostHeader());
|
||||||
} else if (e instanceof ForumInvitationReceivedEvent) {
|
} else if (e instanceof ForumInvitationReceivedEvent) {
|
||||||
|
LOG.info("Forum invitation received, reloading available forums");
|
||||||
loadAvailableForums();
|
loadAvailableForums();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,6 +262,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(g);
|
int position = adapter.findItemPosition(g);
|
||||||
ForumListItem item = adapter.getItemAt(position);
|
ForumListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -270,6 +277,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(g);
|
int position = adapter.findItemPosition(g);
|
||||||
ForumListItem item = adapter.getItemAt(position);
|
ForumListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ public abstract class BaseEventFragment extends BaseFragment implements
|
|||||||
protected volatile EventBus eventBus;
|
protected volatile EventBus eventBus;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public abstract class BaseFragment extends Fragment
|
|||||||
|
|
||||||
public interface BaseFragmentListener extends DestroyableContext {
|
public interface BaseFragmentListener extends DestroyableContext {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
void runOnDbThread(Runnable runnable);
|
void runOnDbThread(Runnable runnable);
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -155,14 +155,14 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package org.briarproject.android.introduction;
|
package org.briarproject.android.introduction;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.briarproject.android.contact.ContactListAdapter;
|
import org.briarproject.android.contact.ContactListAdapter;
|
||||||
import org.briarproject.android.contact.ContactListItem;
|
import org.briarproject.android.contact.ContactListItem;
|
||||||
import org.briarproject.api.identity.AuthorId;
|
import org.briarproject.api.identity.AuthorId;
|
||||||
|
|
||||||
public class ContactChooserAdapter extends ContactListAdapter {
|
@UiThread
|
||||||
|
class ContactChooserAdapter extends ContactListAdapter {
|
||||||
|
|
||||||
private AuthorId localAuthorId;
|
private AuthorId localAuthorId;
|
||||||
|
|
||||||
public ContactChooserAdapter(Context context,
|
ContactChooserAdapter(Context context, OnItemClickListener listener) {
|
||||||
OnItemClickListener listener) {
|
|
||||||
|
|
||||||
super(context, listener);
|
super(context, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ public class ContactChooserAdapter extends ContactListAdapter {
|
|||||||
*
|
*
|
||||||
* @param authorId The ID of the local Author
|
* @param authorId The ID of the local Author
|
||||||
*/
|
*/
|
||||||
public void setLocalAuthor(AuthorId authorId) {
|
void setLocalAuthor(AuthorId authorId) {
|
||||||
localAuthorId = authorId;
|
localAuthorId = authorId;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,18 +45,18 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
private IntroductionActivity introductionActivity;
|
private IntroductionActivity introductionActivity;
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private ContactChooserAdapter adapter;
|
private ContactChooserAdapter adapter;
|
||||||
private int contactId;
|
private ContactId contactId;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
protected volatile Contact c1;
|
volatile Contact c1;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ContactManager contactManager;
|
volatile ContactManager contactManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile IdentityManager identityManager;
|
volatile IdentityManager identityManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ConversationManager conversationManager;
|
volatile ConversationManager conversationManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ConnectionRegistry connectionRegistry;
|
volatile ConnectionRegistry connectionRegistry;
|
||||||
|
|
||||||
public static ContactChooserFragment newInstance() {
|
public static ContactChooserFragment newInstance() {
|
||||||
|
|
||||||
@@ -87,9 +87,7 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
new ContactListAdapter.OnItemClickListener() {
|
new ContactListAdapter.OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(View view, ContactListItem item) {
|
public void onItemClick(View view, ContactListItem item) {
|
||||||
if (c1 == null) {
|
if (c1 == null) throw new IllegalStateException();
|
||||||
throw new RuntimeException("c1 not accountExists");
|
|
||||||
}
|
|
||||||
Contact c2 = item.getContact();
|
Contact c2 = item.getContact();
|
||||||
if (!c1.getLocalAuthorId()
|
if (!c1.getLocalAuthorId()
|
||||||
.equals(c2.getLocalAuthorId())) {
|
.equals(c2.getLocalAuthorId())) {
|
||||||
@@ -113,15 +111,14 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
|
|
||||||
loadContacts();
|
loadContacts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
list.showProgressBar();
|
list.showProgressBar();
|
||||||
}
|
}
|
||||||
@@ -145,7 +142,7 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
AuthorId localAuthorId =
|
AuthorId localAuthorId =
|
||||||
identityManager.getLocalAuthor().getId();
|
identityManager.getLocalAuthor().getId();
|
||||||
for (Contact c : contactManager.getActiveContacts()) {
|
for (Contact c : contactManager.getActiveContacts()) {
|
||||||
if (c.getId().getInt() == contactId) {
|
if (c.getId().equals(contactId)) {
|
||||||
c1 = c;
|
c1 = c;
|
||||||
} else {
|
} else {
|
||||||
ContactId id = c.getId();
|
ContactId id = c.getId();
|
||||||
@@ -176,7 +173,7 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
adapter.setLocalAuthor(localAuthorId);
|
adapter.setLocalAuthor(localAuthorId);
|
||||||
if (contacts.size() == 0) list.showData();
|
if (contacts.isEmpty()) list.showData();
|
||||||
else adapter.addAll(contacts);
|
else adapter.addAll(contacts);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.briarproject.android.ActivityComponent;
|
|||||||
import org.briarproject.android.BriarActivity;
|
import org.briarproject.android.BriarActivity;
|
||||||
import org.briarproject.android.fragment.BaseFragment;
|
import org.briarproject.android.fragment.BaseFragment;
|
||||||
import org.briarproject.api.contact.Contact;
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
|
||||||
// TODO extend the BriarFragmentActivity ?
|
// TODO extend the BriarFragmentActivity ?
|
||||||
public class IntroductionActivity extends BriarActivity implements
|
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";
|
public static final String CONTACT_ID = "briar.CONTACT_ID";
|
||||||
|
|
||||||
private int contactId;
|
private ContactId contactId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
contactId = intent.getIntExtra(CONTACT_ID, -1);
|
int id = intent.getIntExtra(CONTACT_ID, -1);
|
||||||
if (contactId == -1)
|
if (id == -1) throw new IllegalStateException("No ContactId");
|
||||||
throw new IllegalArgumentException("Wrong ContactId");
|
contactId = new ContactId(id);
|
||||||
|
|
||||||
setContentView(R.layout.activity_fragment_container);
|
setContentView(R.layout.activity_fragment_container);
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ public class IntroductionActivity extends BriarActivity implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getContactId() {
|
ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,13 @@ public class AddContactActivity extends BriarActivity
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AddContactActivity.class.getName());
|
Logger.getLogger(AddContactActivity.class.getName());
|
||||||
|
|
||||||
@Inject protected CryptoComponent crypto;
|
@Inject
|
||||||
@Inject protected InvitationTaskFactory invitationTaskFactory;
|
CryptoComponent crypto;
|
||||||
@Inject protected ReferenceManager referenceManager;
|
@Inject
|
||||||
|
InvitationTaskFactory invitationTaskFactory;
|
||||||
|
@Inject
|
||||||
|
ReferenceManager referenceManager;
|
||||||
|
|
||||||
private AddContactView view = null;
|
private AddContactView view = null;
|
||||||
private InvitationTask task = null;
|
private InvitationTask task = null;
|
||||||
private long taskHandle = -1;
|
private long taskHandle = -1;
|
||||||
@@ -52,7 +56,8 @@ public class AddContactActivity extends BriarActivity
|
|||||||
private String contactName = null;
|
private String contactName = null;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject protected volatile IdentityManager identityManager;
|
@Inject
|
||||||
|
volatile IdentityManager identityManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -150,8 +155,8 @@ public class AddContactActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
view.populate();
|
view.populate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,15 +40,13 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
|
|||||||
private static final int STEP_QR = 2;
|
private static final int STEP_QR = 2;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected EventBus eventBus;
|
EventBus eventBus;
|
||||||
|
|
||||||
private Toolbar toolbar;
|
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ContactExchangeTask contactExchangeTask;
|
volatile ContactExchangeTask contactExchangeTask;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile IdentityManager identityManager;
|
volatile IdentityManager identityManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -61,7 +59,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
|
|||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
setContentView(R.layout.activity_plain);
|
setContentView(R.layout.activity_plain);
|
||||||
|
|
||||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
@@ -83,14 +81,14 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,25 +162,16 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
} else {
|
} else {
|
||||||
startListening();
|
startListening();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
openCamera();
|
openCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
releaseCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
stopListening();
|
stopListening();
|
||||||
if (receiver != null) getActivity().unregisterReceiver(receiver);
|
if (receiver != null) getActivity().unregisterReceiver(receiver);
|
||||||
|
releaseCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -132,16 +132,16 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
getPreferenceScreen().getSharedPreferences()
|
getPreferenceScreen().getSharedPreferences()
|
||||||
.registerOnSharedPreferenceChangeListener(this);
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
showPanicApp(PanicResponder.getTriggerPackageName(getActivity()));
|
showPanicApp(PanicResponder.getTriggerPackageName(getActivity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
getPreferenceScreen().getSharedPreferences()
|
getPreferenceScreen().getSharedPreferences()
|
||||||
.unregisterOnSharedPreferenceChangeListener(this);
|
.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class GroupControllerImpl
|
public class GroupControllerImpl extends
|
||||||
extends ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage>
|
ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage>
|
||||||
implements GroupController {
|
implements GroupController {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -48,8 +48,8 @@ public class GroupControllerImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResume() {
|
public void onActivityStart() {
|
||||||
super.onActivityResume();
|
super.onActivityStart();
|
||||||
// TODO: Add new notification manager methods for private groups
|
// TODO: Add new notification manager methods for private groups
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +101,8 @@ public class GroupControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
protected GroupMessage createLocalMessage(String body, long timestamp,
|
protected GroupMessage createLocalMessage(String body, long timestamp,
|
||||||
@Nullable MessageId parentId, LocalAuthor author) {
|
@Nullable MessageId parentId, LocalAuthor author) {
|
||||||
return privateGroupManager
|
return privateGroupManager.createLocalMessage(getGroupId(), body,
|
||||||
.createLocalMessage(getGroupId(), body, timestamp, parentId,
|
timestamp, parentId, author);
|
||||||
author);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,56 +1,51 @@
|
|||||||
package org.briarproject.android.privategroup.list;
|
package org.briarproject.android.privategroup.list;
|
||||||
|
|
||||||
|
import org.briarproject.api.clients.MessageTracker.GroupCount;
|
||||||
import org.briarproject.api.identity.Author;
|
import org.briarproject.api.identity.Author;
|
||||||
|
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||||
import org.briarproject.api.privategroup.PrivateGroup;
|
import org.briarproject.api.privategroup.PrivateGroup;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
|
@NotNullByDefault
|
||||||
class GroupItem {
|
class GroupItem {
|
||||||
|
|
||||||
private final PrivateGroup privateGroup;
|
private final PrivateGroup privateGroup;
|
||||||
private int messageCount;
|
private int messageCount, unreadCount;
|
||||||
private long lastUpdate;
|
private long timestamp;
|
||||||
private int unreadCount;
|
|
||||||
private boolean dissolved;
|
private boolean dissolved;
|
||||||
|
|
||||||
GroupItem(@NotNull PrivateGroup privateGroup, int messageCount,
|
GroupItem(PrivateGroup privateGroup, GroupCount count, boolean dissolved) {
|
||||||
long lastUpdate, int unreadCount, boolean dissolved) {
|
|
||||||
|
|
||||||
this.privateGroup = privateGroup;
|
this.privateGroup = privateGroup;
|
||||||
this.messageCount = messageCount;
|
this.messageCount = count.getMsgCount();
|
||||||
this.lastUpdate = lastUpdate;
|
this.unreadCount = count.getUnreadCount();
|
||||||
this.unreadCount = unreadCount;
|
this.timestamp = count.getLatestMsgTime();
|
||||||
this.dissolved = dissolved;
|
this.dissolved = dissolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMessageHeader(GroupMessageHeader header) {
|
void addMessageHeader(GroupMessageHeader header) {
|
||||||
messageCount++;
|
messageCount++;
|
||||||
if (header.getTimestamp() > lastUpdate) {
|
if (header.getTimestamp() > timestamp) {
|
||||||
lastUpdate = header.getTimestamp();
|
timestamp = header.getTimestamp();
|
||||||
}
|
}
|
||||||
if (!header.isRead()) {
|
if (!header.isRead()) {
|
||||||
unreadCount++;
|
unreadCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
PrivateGroup getPrivateGroup() {
|
PrivateGroup getPrivateGroup() {
|
||||||
return privateGroup;
|
return privateGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
GroupId getId() {
|
GroupId getId() {
|
||||||
return privateGroup.getId();
|
return privateGroup.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
Author getCreator() {
|
Author getCreator() {
|
||||||
return privateGroup.getAuthor();
|
return privateGroup.getAuthor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
String getName() {
|
String getName() {
|
||||||
return privateGroup.getName();
|
return privateGroup.getName();
|
||||||
}
|
}
|
||||||
@@ -63,8 +58,8 @@ class GroupItem {
|
|||||||
return messageCount;
|
return messageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getLastUpdate() {
|
long getTimestamp() {
|
||||||
return lastUpdate;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getUnreadCount() {
|
int getUnreadCount() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
|
|||||||
public int compare(GroupItem a, GroupItem b) {
|
public int compare(GroupItem a, GroupItem b) {
|
||||||
if (a == b) return 0;
|
if (a == b) return 0;
|
||||||
// The group with the latest message comes first
|
// 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;
|
||||||
if (aTime < bTime) return 1;
|
if (aTime < bTime) return 1;
|
||||||
// Break ties by group name
|
// Break ties by group name
|
||||||
@@ -50,7 +50,7 @@ class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
|
|||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(GroupItem a, GroupItem b) {
|
public boolean areContentsTheSame(GroupItem a, GroupItem b) {
|
||||||
return a.getMessageCount() == b.getMessageCount() &&
|
return a.getMessageCount() == b.getMessageCount() &&
|
||||||
a.getLastUpdate() == b.getLastUpdate() &&
|
a.getTimestamp() == b.getTimestamp() &&
|
||||||
a.getUnreadCount() == b.getUnreadCount() &&
|
a.getUnreadCount() == b.getUnreadCount() &&
|
||||||
a.isDissolved() == b.isDissolved();
|
a.isDissolved() == b.isDissolved();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public interface GroupListController extends DbController {
|
|||||||
ResultExceptionHandler<Void, DbException> result);
|
ResultExceptionHandler<Void, DbException> result);
|
||||||
|
|
||||||
interface GroupListListener extends DestroyableContext {
|
interface GroupListListener extends DestroyableContext {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void onGroupMessageAdded(GroupMessageHeader header);
|
void onGroupMessageAdded(GroupMessageHeader header);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.briarproject.android.controller.handler.ResultExceptionHandler;
|
|||||||
import org.briarproject.api.clients.MessageTracker.GroupCount;
|
import org.briarproject.api.clients.MessageTracker.GroupCount;
|
||||||
import org.briarproject.api.db.DatabaseExecutor;
|
import org.briarproject.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.db.NoSuchGroupException;
|
||||||
import org.briarproject.api.event.Event;
|
import org.briarproject.api.event.Event;
|
||||||
import org.briarproject.api.event.EventBus;
|
import org.briarproject.api.event.EventBus;
|
||||||
import org.briarproject.api.event.EventListener;
|
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.event.GroupRemovedEvent;
|
||||||
import org.briarproject.api.identity.IdentityManager;
|
import org.briarproject.api.identity.IdentityManager;
|
||||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||||
import org.briarproject.api.privategroup.PrivateGroup;
|
import org.briarproject.api.privategroup.PrivateGroup;
|
||||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||||
import org.briarproject.api.sync.ClientId;
|
import org.briarproject.api.sync.ClientId;
|
||||||
@@ -29,6 +31,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
public class GroupListControllerImpl extends DbControllerImpl
|
public class GroupListControllerImpl extends DbControllerImpl
|
||||||
@@ -81,59 +84,77 @@ public class GroupListControllerImpl extends DbControllerImpl
|
|||||||
@CallSuper
|
@CallSuper
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof GroupMessageAddedEvent) {
|
if (e instanceof GroupMessageAddedEvent) {
|
||||||
final GroupMessageAddedEvent m = (GroupMessageAddedEvent) e;
|
GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
|
||||||
LOG.info("New group message added");
|
LOG.info("Private group message added");
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
onGroupMessageAdded(g.getHeader());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
listener.onGroupMessageAdded(m.getHeader());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (e instanceof GroupAddedEvent) {
|
} else if (e instanceof GroupAddedEvent) {
|
||||||
final GroupAddedEvent gae = (GroupAddedEvent) e;
|
GroupAddedEvent g = (GroupAddedEvent) e;
|
||||||
ClientId id = gae.getGroup().getClientId();
|
ClientId id = g.getGroup().getClientId();
|
||||||
if (id.equals(groupManager.getClientId())) {
|
if (id.equals(groupManager.getClientId())) {
|
||||||
LOG.info("Private group added");
|
LOG.info("Private group added");
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
onGroupAdded(g.getGroup().getId());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
listener.onGroupAdded(gae.getGroup().getId());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof GroupRemovedEvent) {
|
} else if (e instanceof GroupRemovedEvent) {
|
||||||
final GroupRemovedEvent gre = (GroupRemovedEvent) e;
|
GroupRemovedEvent g = (GroupRemovedEvent) e;
|
||||||
ClientId id = gre.getGroup().getClientId();
|
ClientId id = g.getGroup().getClientId();
|
||||||
if (id.equals(groupManager.getClientId())) {
|
if (id.equals(groupManager.getClientId())) {
|
||||||
LOG.info("Private group removed");
|
LOG.info("Private group removed");
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
onGroupRemoved(g.getGroup().getId());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
listener.onGroupRemoved(gre.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
|
@Override
|
||||||
public void loadGroups(
|
public void loadGroups(
|
||||||
final ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
|
final ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Loading groups from database...");
|
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
Collection<PrivateGroup> groups =
|
Collection<PrivateGroup> groups =
|
||||||
groupManager.getPrivateGroups();
|
groupManager.getPrivateGroups();
|
||||||
List<GroupItem> items = new ArrayList<>(groups.size());
|
List<GroupItem> items = new ArrayList<>(groups.size());
|
||||||
for (PrivateGroup g : groups) {
|
for (PrivateGroup g : groups) {
|
||||||
GroupCount c = groupManager.getGroupCount(g.getId());
|
try {
|
||||||
boolean dissolved = groupManager.isDissolved(g.getId());
|
GroupId id = g.getId();
|
||||||
items.add(new GroupItem(g, c.getMsgCount(),
|
GroupCount count = groupManager.getGroupCount(id);
|
||||||
c.getLatestMsgTime(), c.getUnreadCount(),
|
boolean dissolved = groupManager.isDissolved(id);
|
||||||
dissolved));
|
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);
|
handler.onResult(items);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
@@ -150,9 +171,13 @@ public class GroupListControllerImpl extends DbControllerImpl
|
|||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Removing group from database...");
|
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
groupManager.removePrivateGroup(g);
|
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) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.android.privategroup.list;
|
package org.briarproject.android.privategroup.list;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
@@ -16,7 +15,6 @@ import org.briarproject.R;
|
|||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.android.fragment.BaseFragment;
|
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.GroupListController.GroupListListener;
|
||||||
import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
|
import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
|
||||||
import org.briarproject.android.view.BriarRecyclerView;
|
import org.briarproject.android.view.BriarRecyclerView;
|
||||||
@@ -25,6 +23,7 @@ import org.briarproject.api.privategroup.GroupMessageHeader;
|
|||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -32,6 +31,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
GroupListListener, OnGroupRemoveClickListener {
|
GroupListListener, OnGroupRemoveClickListener {
|
||||||
|
|
||||||
public final static String TAG = GroupListFragment.class.getName();
|
public final static String TAG = GroupListFragment.class.getName();
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
public static GroupListFragment newInstance() {
|
public static GroupListFragment newInstance() {
|
||||||
return new GroupListFragment();
|
return new GroupListFragment();
|
||||||
@@ -114,7 +114,6 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO handle error
|
// TODO handle error
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -122,6 +121,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
@UiThread
|
@UiThread
|
||||||
@Override
|
@Override
|
||||||
public void onGroupMessageAdded(GroupMessageHeader header) {
|
public void onGroupMessageAdded(GroupMessageHeader header) {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(header.getGroupId());
|
int position = adapter.findItemPosition(header.getGroupId());
|
||||||
GroupItem item = adapter.getItemAt(position);
|
GroupItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -139,6 +139,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
@UiThread
|
@UiThread
|
||||||
@Override
|
@Override
|
||||||
public void onGroupRemoved(GroupId groupId) {
|
public void onGroupRemoved(GroupId groupId) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.removeItem(groupId);
|
adapter.removeItem(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,22 +149,25 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadGroups() {
|
private void loadGroups() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
controller.loadGroups(
|
controller.loadGroups(
|
||||||
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<GroupItem> result) {
|
public void onResultUi(Collection<GroupItem> groups) {
|
||||||
if (result.isEmpty()) {
|
if (revision == adapter.getRevision()) {
|
||||||
list.showData();
|
adapter.incrementRevision();
|
||||||
|
if (groups.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(groups);
|
||||||
} else {
|
} else {
|
||||||
adapter.addAll(result);
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadGroups();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExceptionUi(DbException exception) {
|
public void onExceptionUi(DbException exception) {
|
||||||
// TODO handle this error
|
// TODO handle this error
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class GroupViewHolder extends RecyclerView.ViewHolder {
|
|||||||
postCount.setTextColor(
|
postCount.setTextColor(
|
||||||
getColor(ctx, R.color.briar_text_secondary));
|
getColor(ctx, R.color.briar_text_secondary));
|
||||||
|
|
||||||
long lastUpdate = group.getLastUpdate();
|
long lastUpdate = group.getTimestamp();
|
||||||
date.setText(AndroidUtils.formatDate(ctx, lastUpdate));
|
date.setText(AndroidUtils.formatDate(ctx, lastUpdate));
|
||||||
date.setVisibility(VISIBLE);
|
date.setVisibility(VISIBLE);
|
||||||
avatar.setProblem(false);
|
avatar.setProblem(false);
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ public class DevReportActivity extends BaseCrashReportDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
if (chevron.isSelected()) refresh();
|
if (chevron.isSelected()) refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import org.briarproject.api.sync.GroupId;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
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
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ContactManager contactManager;
|
volatile ContactManager contactManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile IdentityManager identityManager;
|
volatile IdentityManager identityManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ForumSharingManager forumSharingManager;
|
volatile ForumSharingManager forumSharingManager;
|
||||||
|
|
||||||
private volatile GroupId groupId;
|
private volatile GroupId groupId;
|
||||||
|
|
||||||
@@ -91,8 +90,9 @@ public class ContactSelectorFragment extends BaseFragment implements
|
|||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
groupId = new GroupId(args.getByteArray(GROUP_ID));
|
byte[] b = args.getByteArray(GROUP_ID);
|
||||||
if (groupId == null) throw new IllegalStateException("No GroupId");
|
if (b == null) throw new IllegalStateException("No GroupId");
|
||||||
|
groupId = new GroupId(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -125,12 +125,16 @@ public class ContactSelectorFragment extends BaseFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
|
loadContacts(selectedContacts);
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedContacts != null)
|
@Override
|
||||||
loadContacts(Collections.unmodifiableCollection(selectedContacts));
|
public void onStop() {
|
||||||
else loadContacts(null);
|
super.onStop();
|
||||||
|
adapter.clear();
|
||||||
|
list.showProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -202,9 +206,8 @@ public class ContactSelectorFragment extends BaseFragment implements
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayContacts(Collections.unmodifiableList(contacts));
|
displayContacts(contacts);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
displayContacts(Collections.<ContactListItem>emptyList());
|
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
@@ -216,8 +219,8 @@ public class ContactSelectorFragment extends BaseFragment implements
|
|||||||
shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
|
shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!contacts.isEmpty()) adapter.addAll(contacts);
|
if (contacts.isEmpty()) list.showData();
|
||||||
else list.showData();
|
else adapter.addAll(contacts);
|
||||||
updateMenuItem();
|
updateMenuItem();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.android.sharing;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.CallSuper;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
protected static final Logger LOG =
|
protected static final Logger LOG =
|
||||||
Logger.getLogger(InvitationsActivity.class.getName());
|
Logger.getLogger(InvitationsActivity.class.getName());
|
||||||
|
|
||||||
private InvitationAdapter adapter;
|
protected InvitationAdapter adapter;
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -42,7 +43,6 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
|
|
||||||
adapter = getAdapter(this, this);
|
adapter = getAdapter(this, this);
|
||||||
|
|
||||||
|
|
||||||
list = (BriarRecyclerView) findViewById(R.id.list);
|
list = (BriarRecyclerView) findViewById(R.id.list);
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
list.setLayoutManager(new LinearLayoutManager(this));
|
list.setLayoutManager(new LinearLayoutManager(this));
|
||||||
@@ -51,21 +51,22 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
loadInvitations(false);
|
loadInvitations(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
list.showProgressBar();
|
list.showProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@CallSuper
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
LOG.info("Contact removed, reloading...");
|
LOG.info("Contact removed, reloading...");
|
||||||
@@ -83,6 +84,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
Toast.makeText(this, res, LENGTH_SHORT).show();
|
Toast.makeText(this, res, LENGTH_SHORT).show();
|
||||||
|
|
||||||
// remove item and finish if it was the last
|
// remove item and finish if it was the last
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.remove(item);
|
adapter.remove(item);
|
||||||
if (adapter.getItemCount() == 0) {
|
if (adapter.getItemCount() == 0) {
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
@@ -101,7 +103,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
|
|
||||||
abstract protected int getDeclineRes();
|
abstract protected int getDeclineRes();
|
||||||
|
|
||||||
protected void displayInvitations(
|
protected void displayInvitations(final int revision,
|
||||||
final Collection<InvitationItem> invitations, final boolean clear) {
|
final Collection<InvitationItem> invitations, final boolean clear) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -109,9 +111,13 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
if (invitations.isEmpty()) {
|
if (invitations.isEmpty()) {
|
||||||
LOG.info("No more invitations available, finishing");
|
LOG.info("No more invitations available, finishing");
|
||||||
finish();
|
finish();
|
||||||
|
} else if (revision == adapter.getRevision()) {
|
||||||
|
adapter.incrementRevision();
|
||||||
|
if (clear) adapter.setItems(invitations);
|
||||||
|
else adapter.addAll(invitations);
|
||||||
} else {
|
} else {
|
||||||
if (clear) adapter.clear();
|
LOG.info("Concurrent update, reloading");
|
||||||
adapter.addAll(invitations);
|
loadInvitations(clear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile BlogManager blogManager;
|
volatile BlogManager blogManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile BlogSharingManager blogSharingManager;
|
volatile BlogSharingManager blogSharingManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -62,31 +62,35 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected InvitationAdapter getAdapter(Context ctx,
|
protected InvitationAdapter getAdapter(Context ctx,
|
||||||
AvailableForumClickListener listener) {
|
AvailableForumClickListener listener) {
|
||||||
return new BlogInvitationAdapter(ctx, listener);
|
return new BlogInvitationAdapter(ctx, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void loadInvitations(final boolean clear) {
|
protected void loadInvitations(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Collection<InvitationItem> invitations = new ArrayList<>();
|
|
||||||
try {
|
try {
|
||||||
|
Collection<InvitationItem> invitations = new ArrayList<>();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
invitations.addAll(blogSharingManager.getInvitations());
|
invitations.addAll(blogSharingManager.getInvitations());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
|
displayInvitations(revision, invitations, clear);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
displayInvitations(invitations, clear);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void respondToInvitation(final InvitationItem item,
|
protected void respondToInvitation(final InvitationItem item,
|
||||||
final boolean accept) {
|
final boolean accept) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@@ -95,6 +99,7 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
try {
|
try {
|
||||||
Blog b = (Blog) item.getShareable();
|
Blog b = (Blog) item.getShareable();
|
||||||
for (Contact c : item.getNewSharers()) {
|
for (Contact c : item.getNewSharers()) {
|
||||||
|
// TODO: What happens if a contact has been removed?
|
||||||
blogSharingManager.respondToInvitation(b, c, accept);
|
blogSharingManager.respondToInvitation(b, c, accept);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -105,10 +110,12 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected int getAcceptRes() {
|
protected int getAcceptRes() {
|
||||||
return R.string.blogs_sharing_joined_toast;
|
return R.string.blogs_sharing_joined_toast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected int getDeclineRes() {
|
protected int getDeclineRes() {
|
||||||
return R.string.blogs_sharing_declined_toast;
|
return R.string.blogs_sharing_declined_toast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ForumManager forumManager;
|
volatile ForumManager forumManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile ForumSharingManager forumSharingManager;
|
volatile ForumSharingManager forumSharingManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -62,31 +62,35 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected InvitationAdapter getAdapter(Context ctx,
|
protected InvitationAdapter getAdapter(Context ctx,
|
||||||
AvailableForumClickListener listener) {
|
AvailableForumClickListener listener) {
|
||||||
return new ForumInvitationAdapter(ctx, listener);
|
return new ForumInvitationAdapter(ctx, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void loadInvitations(final boolean clear) {
|
protected void loadInvitations(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Collection<InvitationItem> invitations = new ArrayList<>();
|
|
||||||
try {
|
try {
|
||||||
|
Collection<InvitationItem> invitations = new ArrayList<>();
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
invitations.addAll(forumSharingManager.getInvitations());
|
invitations.addAll(forumSharingManager.getInvitations());
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
|
displayInvitations(revision, invitations, clear);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
displayInvitations(invitations, clear);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void respondToInvitation(final InvitationItem item,
|
protected void respondToInvitation(final InvitationItem item,
|
||||||
final boolean accept) {
|
final boolean accept) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@@ -95,6 +99,7 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
try {
|
try {
|
||||||
Forum f = (Forum) item.getShareable();
|
Forum f = (Forum) item.getShareable();
|
||||||
for (Contact c : item.getNewSharers()) {
|
for (Contact c : item.getNewSharers()) {
|
||||||
|
// TODO: What happens if a contact has been removed?
|
||||||
forumSharingManager.respondToInvitation(f, c, accept);
|
forumSharingManager.respondToInvitation(f, c, accept);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -105,10 +110,12 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected int getAcceptRes() {
|
protected int getAcceptRes() {
|
||||||
return R.string.forum_joined_toast;
|
return R.string.forum_joined_toast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected int getDeclineRes() {
|
protected int getDeclineRes() {
|
||||||
return R.string.forum_declined_toast;
|
return R.string.forum_declined_toast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,13 +63,21 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
|
|
||||||
loadSharedBy();
|
loadSharedBy();
|
||||||
loadSharedWith();
|
loadSharedWith();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
sharedByAdapter.clear();
|
||||||
|
sharedByList.showProgressBar();
|
||||||
|
sharedWithAdapter.clear();
|
||||||
|
sharedWithList.showProgressBar();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
// Handle presses on the action bar items
|
// Handle presses on the action bar items
|
||||||
@@ -97,11 +105,11 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadSharedBy() {
|
private void loadSharedBy() {
|
||||||
dbController.runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
List<ContactListItem> contactItems = new ArrayList<>();
|
|
||||||
try {
|
try {
|
||||||
|
List<ContactListItem> contactItems = new ArrayList<>();
|
||||||
for (Contact c : getSharedBy()) {
|
for (Contact c : getSharedBy()) {
|
||||||
LocalAuthor localAuthor = identityManager
|
LocalAuthor localAuthor = identityManager
|
||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
@@ -110,11 +118,11 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
groupId, new GroupCount(0, 0, 0));
|
groupId, new GroupCount(0, 0, 0));
|
||||||
contactItems.add(item);
|
contactItems.add(item);
|
||||||
}
|
}
|
||||||
|
displaySharedBy(contactItems);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
displaySharedBy(contactItems);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -123,21 +131,18 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (contacts.isEmpty()) {
|
if (contacts.isEmpty()) sharedByList.showData();
|
||||||
sharedByList.showData();
|
else sharedByAdapter.addAll(contacts);
|
||||||
} else {
|
|
||||||
sharedByAdapter.addAll(contacts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSharedWith() {
|
private void loadSharedWith() {
|
||||||
dbController.runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
List<ContactListItem> contactItems = new ArrayList<>();
|
|
||||||
try {
|
try {
|
||||||
|
List<ContactListItem> contactItems = new ArrayList<>();
|
||||||
for (Contact c : getSharedWith()) {
|
for (Contact c : getSharedWith()) {
|
||||||
LocalAuthor localAuthor = identityManager
|
LocalAuthor localAuthor = identityManager
|
||||||
.getLocalAuthor(c.getLocalAuthorId());
|
.getLocalAuthor(c.getLocalAuthorId());
|
||||||
@@ -146,11 +151,11 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
groupId, new GroupCount(0, 0, 0));
|
groupId, new GroupCount(0, 0, 0));
|
||||||
contactItems.add(item);
|
contactItems.add(item);
|
||||||
}
|
}
|
||||||
|
displaySharedWith(contactItems);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
displaySharedWith(contactItems);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -159,11 +164,8 @@ abstract class SharingStatusActivity extends BriarActivity {
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (contacts.isEmpty()) {
|
if (contacts.isEmpty()) sharedWithList.showData();
|
||||||
sharedWithList.showData();
|
else sharedWithAdapter.addAll(contacts);
|
||||||
} else {
|
|
||||||
sharedWithAdapter.addAll(contacts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.support.annotation.UiThread;
|
|||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
|
||||||
|
import org.briarproject.android.util.VersionedAdapter;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -16,21 +17,23 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
@UiThread
|
|
||||||
public abstract class ThreadItemAdapter<I extends ThreadItem>
|
public abstract class ThreadItemAdapter<I extends ThreadItem>
|
||||||
extends RecyclerView.Adapter<ThreadItemViewHolder<I>> {
|
extends RecyclerView.Adapter<ThreadItemViewHolder<I>>
|
||||||
|
implements VersionedAdapter {
|
||||||
|
|
||||||
static final int UNDEFINED = -1;
|
static final int UNDEFINED = -1;
|
||||||
|
|
||||||
private final NestedTreeList<I> items = new NestedTreeList<>();
|
private final NestedTreeList<I> items = new NestedTreeList<>();
|
||||||
private final Map<I, ValueAnimator> animatingItems = new HashMap<>();
|
private final Map<I, ValueAnimator> animatingItems = new HashMap<>();
|
||||||
|
private final ThreadItemListener<I> listener;
|
||||||
|
private final LinearLayoutManager layoutManager;
|
||||||
|
|
||||||
// highlight not dependant on time
|
// highlight not dependant on time
|
||||||
private I replyItem;
|
private I replyItem;
|
||||||
// temporary highlight
|
// temporary highlight
|
||||||
private I addedItem;
|
private I addedItem;
|
||||||
|
|
||||||
private final ThreadItemListener<I> listener;
|
private volatile int revision = 0;
|
||||||
private final LinearLayoutManager layoutManager;
|
|
||||||
|
|
||||||
public ThreadItemAdapter(ThreadItemListener<I> listener,
|
public ThreadItemAdapter(ThreadItemListener<I> listener,
|
||||||
LinearLayoutManager layoutManager) {
|
LinearLayoutManager layoutManager) {
|
||||||
@@ -290,6 +293,17 @@ public abstract class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
animatingItems.remove(item);
|
animatingItems.remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
@Override
|
||||||
|
public void incrementRevision() {
|
||||||
|
revision++;
|
||||||
|
}
|
||||||
|
|
||||||
protected interface ThreadItemListener<I> {
|
protected interface ThreadItemListener<I> {
|
||||||
|
|
||||||
void onItemVisible(I item);
|
void onItemVisible(I item);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.support.design.widget.Snackbar.make;
|
import static android.support.design.widget.Snackbar.make;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
@@ -42,6 +43,9 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
protected static final String KEY_INPUT_VISIBILITY = "inputVisibility";
|
protected static final String KEY_INPUT_VISIBILITY = "inputVisibility";
|
||||||
protected static final String KEY_REPLY_ID = "replyId";
|
protected static final String KEY_REPLY_ID = "replyId";
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(ThreadListActivity.class.getName());
|
||||||
|
|
||||||
protected A adapter;
|
protected A adapter;
|
||||||
protected BriarRecyclerView list;
|
protected BriarRecyclerView list;
|
||||||
protected TextInputView textInput;
|
protected TextInputView textInput;
|
||||||
@@ -75,7 +79,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
|
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
byte[] replyIdBytes = state.getByteArray(KEY_REPLY_ID);
|
byte[] replyIdBytes = state.getByteArray(KEY_REPLY_ID);
|
||||||
if(replyIdBytes != null) replyId = new MessageId(replyIdBytes);
|
if (replyIdBytes != null) replyId = new MessageId(replyIdBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadItems();
|
loadItems();
|
||||||
@@ -106,18 +110,24 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
protected abstract void onNamedGroupLoaded(G groupItem);
|
protected abstract void onNamedGroupLoaded(G groupItem);
|
||||||
|
|
||||||
private void loadItems() {
|
private void loadItems() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
getController().loadItems(
|
getController().loadItems(
|
||||||
new UiResultExceptionHandler<Collection<I>, DbException>(
|
new UiResultExceptionHandler<Collection<I>, DbException>(this) {
|
||||||
this) {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<I> items) {
|
public void onResultUi(Collection<I> items) {
|
||||||
if (items.isEmpty()) {
|
if (revision == adapter.getRevision()) {
|
||||||
list.showData();
|
adapter.incrementRevision();
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
list.showData();
|
||||||
|
} else {
|
||||||
|
adapter.setItems(items);
|
||||||
|
list.showData();
|
||||||
|
if (replyId != null)
|
||||||
|
adapter.setReplyItemById(replyId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
adapter.setItems(items);
|
LOG.info("Concurrent update, reloading");
|
||||||
list.showData();
|
loadItems();
|
||||||
if (replyId != null)
|
|
||||||
adapter.setReplyItemById(replyId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,35 +141,33 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onStart() {
|
||||||
super.onResume();
|
super.onStart();
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onStop() {
|
||||||
super.onPause();
|
super.onStop();
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
textInput.setVisibility(
|
boolean visible = savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY);
|
||||||
savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ?
|
textInput.setVisibility(visible ? VISIBLE : GONE);
|
||||||
VISIBLE : GONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putBoolean(KEY_INPUT_VISIBILITY,
|
boolean visible = textInput.getVisibility() == VISIBLE;
|
||||||
textInput.getVisibility() == VISIBLE);
|
outState.putBoolean(KEY_INPUT_VISIBILITY, visible);
|
||||||
ThreadItem replyItem = adapter.getReplyItem();
|
ThreadItem replyItem = adapter.getReplyItem();
|
||||||
if (replyItem != null) {
|
if (replyItem != null) {
|
||||||
outState.putByteArray(KEY_REPLY_ID,
|
outState.putByteArray(KEY_REPLY_ID, replyItem.getId().getBytes());
|
||||||
replyItem.getId().getBytes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +281,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addItem(final I item, boolean isLocal) {
|
protected void addItem(final I item, boolean isLocal) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
if (isLocal && adapter.isVisible(item)) {
|
if (isLocal && adapter.isVisible(item)) {
|
||||||
displaySnackbarShort(getItemPostedString());
|
displaySnackbarShort(getItemPostedString());
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
private final Map<MessageId, String> bodyCache =
|
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private volatile GroupId groupId;
|
private volatile GroupId groupId;
|
||||||
|
|
||||||
@@ -82,14 +81,14 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResume() {
|
public void onActivityStart() {
|
||||||
notificationManager.blockNotification(getGroupId());
|
notificationManager.blockNotification(getGroupId());
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
public void onActivityPause() {
|
public void onActivityStop() {
|
||||||
notificationManager.unblockNotification(getGroupId());
|
notificationManager.unblockNotification(getGroupId());
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
}
|
}
|
||||||
@@ -127,8 +126,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
G groupItem = loadNamedGroup();
|
G groupItem = loadNamedGroup();
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(
|
LOG.info("Loading group took " + duration + " ms");
|
||||||
"Loading named group took " + duration + " ms");
|
|
||||||
handler.onResult(groupItem);
|
handler.onResult(groupItem);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
@@ -149,7 +147,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Loading items...");
|
|
||||||
try {
|
try {
|
||||||
// Load headers
|
// Load headers
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
@@ -193,8 +190,8 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Loading item...");
|
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
String body;
|
String body;
|
||||||
if (!bodyCache.containsKey(header.getId())) {
|
if (!bodyCache.containsKey(header.getId())) {
|
||||||
body = loadMessageBody(header.getId());
|
body = loadMessageBody(header.getId());
|
||||||
@@ -202,6 +199,9 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
} else {
|
} else {
|
||||||
body = bodyCache.get(header.getId());
|
body = bodyCache.get(header.getId());
|
||||||
}
|
}
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Loading item took " + duration + " ms");
|
||||||
I item = buildItem(header, body);
|
I item = buildItem(header, body);
|
||||||
handler.onResult(item);
|
handler.onResult(item);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -250,12 +250,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
LocalAuthor author = identityManager.getLocalAuthor();
|
LocalAuthor author = identityManager.getLocalAuthor();
|
||||||
long timestamp = getLatestTimestamp();
|
long timestamp = getLatestTimestamp();
|
||||||
timestamp =
|
timestamp = Math.max(timestamp, clock.currentTimeMillis());
|
||||||
Math.max(timestamp, clock.currentTimeMillis());
|
long duration = System.currentTimeMillis() - now;
|
||||||
createMessage(body, timestamp, parentId, author,
|
if (LOG.isLoggable(INFO)) {
|
||||||
handler);
|
LOG.info("Loading identity and timestamp took " +
|
||||||
|
duration + " ms");
|
||||||
|
}
|
||||||
|
createMessage(body, timestamp, parentId, author, handler);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -274,8 +278,11 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
cryptoExecutor.execute(new Runnable() {
|
cryptoExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Creating message...");
|
long now = System.currentTimeMillis();
|
||||||
M msg = createLocalMessage(body, timestamp, parentId, author);
|
M msg = createLocalMessage(body, timestamp, parentId, author);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Creating message took " + duration + " ms");
|
||||||
storePost(msg, body, handler);
|
storePost(msg, body, handler);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -291,7 +298,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
LOG.info("Store message...");
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
H header = addLocalMessage(msg);
|
H header = addLocalMessage(msg);
|
||||||
bodyCache.put(msg.getMessage().getId(), body);
|
bodyCache.put(msg.getMessage().getId(), body);
|
||||||
@@ -354,10 +360,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkGroupId() {
|
private void checkGroupId() {
|
||||||
if (groupId == null) {
|
if (groupId == null) throw new IllegalStateException();
|
||||||
throw new IllegalStateException(
|
|
||||||
"You must set the GroupId before the controller is started.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.android.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.util.SortedList;
|
import android.support.v7.util.SortedList;
|
||||||
import android.support.v7.widget.RecyclerView.Adapter;
|
import android.support.v7.widget.RecyclerView.Adapter;
|
||||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||||
@@ -11,11 +12,13 @@ import java.util.Collection;
|
|||||||
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
import static android.support.v7.util.SortedList.INVALID_POSITION;
|
||||||
|
|
||||||
public abstract class BriarAdapter<T, V extends ViewHolder>
|
public abstract class BriarAdapter<T, V extends ViewHolder>
|
||||||
extends Adapter<V> {
|
extends Adapter<V> implements VersionedAdapter {
|
||||||
|
|
||||||
protected final Context ctx;
|
protected final Context ctx;
|
||||||
protected final SortedList<T> items;
|
protected final SortedList<T> items;
|
||||||
|
|
||||||
|
private volatile int revision = 0;
|
||||||
|
|
||||||
public BriarAdapter(Context ctx, Class<T> c) {
|
public BriarAdapter(Context ctx, Class<T> c) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.items = new SortedList<>(c, new SortedList.Callback<T>() {
|
this.items = new SortedList<>(c, new SortedList.Callback<T>() {
|
||||||
@@ -75,6 +78,13 @@ public abstract class BriarAdapter<T, V extends ViewHolder>
|
|||||||
this.items.addAll(items);
|
this.items.addAll(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setItems(Collection<T> items) {
|
||||||
|
this.items.beginBatchedUpdates();
|
||||||
|
this.items.clear();
|
||||||
|
this.items.addAll(items);
|
||||||
|
this.items.endBatchedUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public T getItemAt(int position) {
|
public T getItemAt(int position) {
|
||||||
if (position == INVALID_POSITION || position >= items.size()) {
|
if (position == INVALID_POSITION || position >= items.size()) {
|
||||||
@@ -103,4 +113,14 @@ public abstract class BriarAdapter<T, V extends ViewHolder>
|
|||||||
return items.size() == 0;
|
return items.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
@Override
|
||||||
|
public void incrementRevision() {
|
||||||
|
revision++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,17 +1,25 @@
|
|||||||
package org.briarproject.api.crypto;
|
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.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import javax.inject.Qualifier;
|
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.
|
||||||
|
* <p>
|
||||||
|
* 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
|
@Qualifier
|
||||||
@Target({FIELD, METHOD, PARAMETER})
|
@Target({FIELD, METHOD, PARAMETER})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface CryptoExecutor {}
|
public @interface CryptoExecutor {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
package org.briarproject.api.db;
|
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.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import javax.inject.Qualifier;
|
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.
|
||||||
* <p>
|
* <p>
|
||||||
* The contract of this executor is that tasks are executed in the order
|
* The contract of this executor is that tasks are run in the order they're
|
||||||
* they're submitted, tasks are not executed concurrently, and submitting a
|
* submitted, tasks are not run concurrently, and submitting a task will never
|
||||||
* task will never block.
|
* block. Tasks must not run indefinitely. Tasks submitted during shutdown are
|
||||||
|
* discarded.
|
||||||
*/
|
*/
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Target({ FIELD, METHOD, PARAMETER })
|
@Target({ FIELD, METHOD, PARAMETER })
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.api.event;
|
package org.briarproject.api.event;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.messaging.PrivateMessageHeader;
|
import org.briarproject.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
@@ -9,11 +10,13 @@ import org.briarproject.api.sync.GroupId;
|
|||||||
public class PrivateMessageReceivedEvent extends Event {
|
public class PrivateMessageReceivedEvent extends Event {
|
||||||
|
|
||||||
private final PrivateMessageHeader messageHeader;
|
private final PrivateMessageHeader messageHeader;
|
||||||
|
private final ContactId contactId;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader,
|
public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader,
|
||||||
GroupId groupId) {
|
ContactId contactId, GroupId groupId) {
|
||||||
this.messageHeader = messageHeader;
|
this.messageHeader = messageHeader;
|
||||||
|
this.contactId = contactId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +24,10 @@ public class PrivateMessageReceivedEvent extends Event {
|
|||||||
return messageHeader;
|
return messageHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
public GroupId getGroupId() {
|
public GroupId getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
package org.briarproject.api.lifecycle;
|
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.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import javax.inject.Qualifier;
|
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.
|
||||||
|
* <p>
|
||||||
|
* 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
|
@Qualifier
|
||||||
@Target({ FIELD, METHOD, PARAMETER })
|
@Target({FIELD, METHOD, PARAMETER})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface IoExecutor {}
|
public @interface IoExecutor {
|
||||||
|
}
|
||||||
@@ -102,10 +102,11 @@ class MessagingManagerImpl extends ConversationClientImpl
|
|||||||
boolean local = meta.getBoolean("local");
|
boolean local = meta.getBoolean("local");
|
||||||
boolean read = meta.getBoolean(MSG_KEY_READ);
|
boolean read = meta.getBoolean(MSG_KEY_READ);
|
||||||
PrivateMessageHeader header = new PrivateMessageHeader(
|
PrivateMessageHeader header = new PrivateMessageHeader(
|
||||||
m.getId(), m.getGroupId(), timestamp, contentType, local, read,
|
m.getId(), groupId, timestamp, contentType, local, read,
|
||||||
false, false);
|
false, false);
|
||||||
|
ContactId contactId = getContactId(txn, groupId);
|
||||||
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
|
PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
|
||||||
header, groupId);
|
header, contactId, groupId);
|
||||||
txn.attach(event);
|
txn.attach(event);
|
||||||
trackIncomingMessage(txn, m);
|
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
|
@Override
|
||||||
public ContactId getContactId(GroupId g) throws DbException {
|
public ContactId getContactId(GroupId g) throws DbException {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user