diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java index eaeb7a06ec1c15fbc58e42a2d27c03bb8124eda8..6ae01b8a53ad11cac4857179ccf52f41c9b577b2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/DbControllerImpl.java @@ -17,7 +17,7 @@ public class DbControllerImpl implements DbController { private static final Logger LOG = Logger.getLogger(DbControllerImpl.class.getName()); - private final Executor dbExecutor; + protected final Executor dbExecutor; private final LifecycleManager lifecycleManager; @Inject diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java index 4c52f6154c90103da580c4206ffc2dd3b4a882fb..8d97e7810063d4a4d20209a469220b5a2b7e8f47 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumControllerImpl.java @@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.forum.ForumController.ForumListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumInvitationResponse; @@ -55,10 +56,10 @@ class ForumControllerImpl extends LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, ForumManager forumManager, ForumSharingManager forumSharingManager, - EventBus eventBus, Clock clock, + EventBus eventBus, Clock clock, MessageTracker messageTracker, AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager); + eventBus, clock, notificationManager, messageTracker); this.forumManager = forumManager; this.forumSharingManager = forumSharingManager; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java index 0c75305591d4220540a76c85683760b273b31d76..db6029e57c002ad2f8365ee7cc915670b4e7c386 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/conversation/GroupControllerImpl.java @@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler; import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener; import org.briarproject.briar.android.threaded.ThreadListControllerImpl; import org.briarproject.briar.api.android.AndroidNotificationManager; +import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.privategroup.GroupMember; import org.briarproject.briar.api.privategroup.GroupMessage; @@ -60,9 +61,10 @@ class GroupControllerImpl extends @CryptoExecutor Executor cryptoExecutor, PrivateGroupManager privateGroupManager, GroupMessageFactory groupMessageFactory, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager) { + MessageTracker messageTracker, Clock clock, + AndroidNotificationManager notificationManager) { super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor, - eventBus, clock, notificationManager); + eventBus, clock, notificationManager, messageTracker); this.privateGroupManager = privateGroupManager; this.groupMessageFactory = groupMessageFactory; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java index 0a36ac80ec301f1f1a56e900726267f9b40e1751..99a4a3335afcef45a27a536231ce5658caca3c15 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemAdapter.java @@ -66,17 +66,7 @@ public class ThreadItemAdapter<I extends ThreadItem> revision++; } - // Useful when the adapter has not calculated the dimension yet - void postSetItemWithIdVisible(@Nullable final MessageId messageId) { - new Handler().post(new Runnable() { - @Override - public void run() { - setItemWithIdVisible(messageId); - } - }); - } - - void setItemWithIdVisible(@Nullable MessageId messageId) { + void setItemWithIdVisible(MessageId messageId) { if (messageId != null) { int pos = 0; for (I item : items) { @@ -169,7 +159,7 @@ public class ThreadItemAdapter<I extends ThreadItem> /** * Returns the position of the first unread item below the current viewport */ - public int getVisibleUnreadPosBottom() { + int getVisibleUnreadPosBottom() { final int positionBottom = layoutManager.findLastVisibleItemPosition(); if (positionBottom == NO_POSITION) return NO_POSITION; for (int i = positionBottom + 1; i < items.size(); i++) { @@ -181,7 +171,7 @@ public class ThreadItemAdapter<I extends ThreadItem> /** * Returns the position of the first unread item above the current viewport */ - public int getVisibleUnreadPosTop() { + int getVisibleUnreadPosTop() { final int positionTop = layoutManager.findFirstVisibleItemPosition(); int position = NO_POSITION; for (int i = 0; i < items.size(); i++) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java index 53d6ed633a89704ed9351b6f6b5527128833e4ee..d4f067c2f72ecba9706a26d0dc95df3ce034864b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemList.java @@ -9,7 +9,7 @@ import javax.annotation.Nullable; public interface ThreadItemList<I extends ThreadItem> extends List<I> { @Nullable - MessageId getBottomVisibleItemId(); + MessageId getFirstVisibleItemId(); void setBottomVisibleItemId(@Nullable MessageId bottomVisibleItemId); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java index 880d297391fc5d6936266fa65a3b58e5499ad4e1..f6fb80e68246d2f55b7630bb648072feaa415874 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadItemListImpl.java @@ -12,7 +12,7 @@ public class ThreadItemListImpl<I extends ThreadItem> extends ArrayList<I> private MessageId bottomVisibleItemId; @Override - public MessageId getBottomVisibleItemId() { + public MessageId getFirstVisibleItemId() { return bottomVisibleItemId; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java index 68cec97a2789860c3929939c17b6024747d8487a..b62f35c772dce2206c6c91f04de8bbae7614e20b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java @@ -149,11 +149,12 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI @Override @Nullable - public MessageId getLastVisibleMessageId() { + public MessageId getFirstVisibleMessageId() { if (layoutManager != null && adapter != null) { int position = - layoutManager.findLastCompletelyVisibleItemPosition(); - return adapter.getItemAt(position).getId(); + layoutManager.findFirstVisibleItemPosition(); + I i = adapter.getItemAt(position); + return i == null ? null : adapter.getItemAt(position).getId(); } return null; } @@ -190,10 +191,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI if (items.isEmpty()) { list.showData(); } else { - adapter.setItems(items); - adapter.postSetItemWithIdVisible( - items.getBottomVisibleItemId()); - list.showData(); + initList(items); updateTextInput(replyId); } } else { @@ -209,6 +207,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI }); } + private void initList(final ThreadItemList<I> items) { + adapter.setItems(items); + MessageId messageId = items.getFirstVisibleItemId(); + if (messageId != null) + adapter.setItemWithIdVisible(messageId); + updateUnreadCount(); + list.showData(); + } + protected void loadSharingContacts() { getController().loadSharingContacts( new UiResultExceptionHandler<Collection<ContactId>, DbException>( diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java index 45aa69a0ac6a819ae2d56ba6015cae293fa2abd8..d39c8b453a6c1c5852d9c56663edd1d7ca0fe4fa 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListController.java @@ -56,7 +56,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem interface ThreadListDataSource extends DestroyableContext { @UiThread @Nullable - MessageId getLastVisibleMessageId(); + MessageId getFirstVisibleMessageId(); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java index c61b354583269ff34cf44222a0cdfe6769fe6eac..add7a977668cb62d24c3909f407c7134530d1d43 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListControllerImpl.java @@ -34,8 +34,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.logging.Logger; -import javax.inject.Inject; - import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; @@ -56,20 +54,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T protected final AndroidNotificationManager notificationManager; protected final Executor cryptoExecutor; protected final Clock clock; + private final MessageTracker messageTracker; protected volatile L listener; - @Inject - MessageTracker messageTracker; protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, LifecycleManager lifecycleManager, IdentityManager identityManager, @CryptoExecutor Executor cryptoExecutor, EventBus eventBus, - Clock clock, AndroidNotificationManager notificationManager) { + Clock clock, AndroidNotificationManager notificationManager, + MessageTracker messageTracker) { super(dbExecutor, lifecycleManager); this.identityManager = identityManager; this.cryptoExecutor = cryptoExecutor; this.notificationManager = notificationManager; this.clock = clock; this.eventBus = eventBus; + this.messageTracker = messageTracker; } @Override @@ -100,14 +99,19 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @Override public void onActivityDestroy() { - try { - messageTracker - .storeMessageId(groupId, - listener.getLastVisibleMessageId()); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } + dbExecutor.execute(new Runnable() { + @Override + public void run() { + try { + messageTracker + .storeMessageId(groupId, + listener.getFirstVisibleMessageId()); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } + } + }); } @CallSuper @@ -304,19 +308,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T @DatabaseExecutor protected abstract void deleteNamedGroup(G groupItem) throws DbException; - private ThreadItemList<I> buildItems(Collection<H> headers) { + private ThreadItemList<I> buildItems(Collection<H> headers) + throws DbException { ThreadItemList<I> items = new ThreadItemListImpl<>(); for (H h : headers) { items.add(buildItem(h, bodyCache.get(h.getId()))); } - try { - MessageId msgId = messageTracker.loadStoredMessageId(groupId); - if (LOG.isLoggable(INFO)) - LOG.info("Loaded last top visible message id " + msgId); - items.setBottomVisibleItemId(msgId); - } catch (DbException e) { - e.printStackTrace(); - } + MessageId msgId = messageTracker.loadStoredMessageId(groupId); + if (LOG.isLoggable(INFO)) + LOG.info("Loaded last top visible message id " + msgId); + items.setBottomVisibleItemId(msgId); return items; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java index e7f4fa92f5387377a72ea82ba02f7b0d1b3ae9bf..4a5360043e21128e68b15c276db786f1d7c01d14 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/UnreadMessageButton.java @@ -36,8 +36,7 @@ public class UnreadMessageButton extends FrameLayout { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater - .inflate(R.layout.unread_message_button, this, true); + inflater.inflate(R.layout.unread_message_button, this, true); fab = (FloatingActionButton) findViewById(R.id.fab); unread = (TextView) findViewById(R.id.unreadCountView); @@ -64,15 +63,11 @@ public class UnreadMessageButton extends FrameLayout { public void setUnreadCount(int count) { if (count == 0) { - fab.setVisibility(GONE); -// fab.hide(); - unread.setVisibility(GONE); + setVisibility(INVISIBLE); } else { // FIXME: Use animations when upgrading to support library 24.2.0 // https://code.google.com/p/android/issues/detail?id=216469 - fab.setVisibility(VISIBLE); -// if (!fab.isShown()) fab.show(); - unread.setVisibility(VISIBLE); + setVisibility(VISIBLE); unread.setText(String.valueOf(count)); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6f841703fe67468ff4fe8c8847ee2f2bb7a1d330 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/client/MessageTrackerTest.java @@ -0,0 +1,57 @@ +package org.briarproject.briar.client; + +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.test.TestUtils; +import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.test.BriarTestCase; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import static org.briarproject.briar.client.MessageTrackerConstants.GROUP_KEY_STORED_MESSAGE_ID; + +public class MessageTrackerTest extends BriarTestCase { + + protected final Mockery context = new Mockery(); + protected final GroupId groupId = new GroupId(TestUtils.getRandomId()); + protected final ClientHelper clientHelper = + context.mock(ClientHelper.class); + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final MessageId messageId = new MessageId(TestUtils.getRandomId()); + private final MessageTracker messageTracker = + new MessageTrackerImpl(db, clientHelper); + private final BdfDictionary dictionary = BdfDictionary.of( + new BdfEntry(GROUP_KEY_STORED_MESSAGE_ID, messageId) + ); + + @Test + public void testMessageStore() throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).mergeGroupMetadata(groupId, dictionary); + }}); + messageTracker.storeMessageId(groupId, messageId); + } + + @Test + public void testMessageLoad() throws Exception { + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(groupId); + will(returnValue(dictionary)); + }}); + MessageId loadedId = messageTracker.loadStoredMessageId(groupId); + Assert.assertNotNull(loadedId); + Assert.assertTrue(messageId.equals(loadedId)); + } + + @After + public void checkExpectations() { + context.assertIsSatisfied(); + } +} diff --git a/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java b/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java index 09805ce44b1cb4d07cc45796ed5b830abab7e7a7..30567fdf225431c37ef54d27fc1908c2d2e7c9e1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/forum/ForumManagerTest.java @@ -1,10 +1,7 @@ package org.briarproject.briar.forum; -import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.TestDatabaseModule; -import org.briarproject.bramble.test.TestUtils; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumManager; import org.briarproject.briar.api.forum.ForumPost; @@ -13,7 +10,6 @@ import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTestComponent; import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -227,18 +223,4 @@ public class ForumManagerTest assertEquals(1, forumManager1.getPostHeaders(g1).size()); } - @Test - public void testMessageStoreAndLoad() { - MessageId msgId = new MessageId(TestUtils.getRandomId()); - MessageId loadedId = null; - try { - messageTracker0.storeMessageId(groupId0, msgId); - loadedId = messageTracker0.loadStoredMessageId(groupId0); - } catch (DbException e) { - e.printStackTrace(); - } - Assert.assertNotNull(loadedId); - Assert.assertTrue(msgId.equals(loadedId)); - } - }