mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Implement conversation data persistence
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
<string name="contact_list_button">Contacts</string>
|
<string name="contact_list_button">Contacts</string>
|
||||||
<string name="delete_contact">Delete contact</string>
|
<string name="delete_contact">Delete contact</string>
|
||||||
<string name="contact_deleted_toast">Contact deleted</string>
|
<string name="contact_deleted_toast">Contact deleted</string>
|
||||||
|
<string name="contact_deletion_failed_toast">Failed to delete contact</string>
|
||||||
<string name="forums_button">Forums</string>
|
<string name="forums_button">Forums</string>
|
||||||
<string name="settings_button">Settings</string>
|
<string name="settings_button">Settings</string>
|
||||||
<string name="sign_out_button">Sign Out</string>
|
<string name="sign_out_button">Sign Out</string>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import org.briarproject.android.contact.ConversationController;
|
||||||
|
import org.briarproject.android.contact.ConversationControllerImpl;
|
||||||
import org.briarproject.android.controller.BriarController;
|
import org.briarproject.android.controller.BriarController;
|
||||||
import org.briarproject.android.controller.BriarControllerImpl;
|
import org.briarproject.android.controller.BriarControllerImpl;
|
||||||
import org.briarproject.android.controller.ConfigController;
|
import org.briarproject.android.controller.ConfigController;
|
||||||
@@ -91,6 +93,14 @@ public class ActivityModule {
|
|||||||
return dbController;
|
return dbController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
@Provides
|
||||||
|
protected ConversationController provideConversationController(
|
||||||
|
ConversationControllerImpl conversationController) {
|
||||||
|
activity.addLifecycleController(conversationController);
|
||||||
|
return conversationController;
|
||||||
|
}
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
@Provides
|
@Provides
|
||||||
protected ForumController provideForumController(
|
protected ForumController provideForumController(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.CoreModule;
|
|||||||
import org.briarproject.android.api.AndroidExecutor;
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
import org.briarproject.android.api.ReferenceManager;
|
import org.briarproject.android.api.ReferenceManager;
|
||||||
|
import org.briarproject.android.contact.ConversationPersistentData;
|
||||||
import org.briarproject.android.forum.ForumPersistentData;
|
import org.briarproject.android.forum.ForumPersistentData;
|
||||||
import org.briarproject.android.report.BriarReportSender;
|
import org.briarproject.android.report.BriarReportSender;
|
||||||
import org.briarproject.api.contact.ContactExchangeTask;
|
import org.briarproject.api.contact.ContactExchangeTask;
|
||||||
@@ -113,6 +114,8 @@ public interface AndroidComponent extends CoreEagerSingletons {
|
|||||||
|
|
||||||
AndroidExecutor androidExecutor();
|
AndroidExecutor androidExecutor();
|
||||||
|
|
||||||
|
ConversationPersistentData conversationPersistentData();
|
||||||
|
|
||||||
ForumPersistentData forumPersistentData();
|
ForumPersistentData forumPersistentData();
|
||||||
|
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Application;
|
|||||||
|
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
import org.briarproject.android.api.ReferenceManager;
|
import org.briarproject.android.api.ReferenceManager;
|
||||||
|
import org.briarproject.android.contact.ConversationPersistentData;
|
||||||
import org.briarproject.android.forum.ForumPersistentData;
|
import org.briarproject.android.forum.ForumPersistentData;
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.crypto.PublicKey;
|
import org.briarproject.api.crypto.PublicKey;
|
||||||
@@ -138,6 +139,12 @@ public class AppModule {
|
|||||||
return notificationManager;
|
return notificationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ConversationPersistentData provideConversationPersistence() {
|
||||||
|
return new ConversationPersistentData();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ForumPersistentData provideForumPersistence() {
|
ForumPersistentData provideForumPersistence() {
|
||||||
|
|||||||
@@ -27,30 +27,12 @@ import org.briarproject.R;
|
|||||||
import org.briarproject.android.ActivityComponent;
|
import org.briarproject.android.ActivityComponent;
|
||||||
import org.briarproject.android.BriarActivity;
|
import org.briarproject.android.BriarActivity;
|
||||||
import org.briarproject.android.api.AndroidNotificationManager;
|
import org.briarproject.android.api.AndroidNotificationManager;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
import org.briarproject.android.introduction.IntroductionActivity;
|
import org.briarproject.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.android.util.BriarRecyclerView;
|
import org.briarproject.android.util.BriarRecyclerView;
|
||||||
import org.briarproject.api.FormatException;
|
|
||||||
import org.briarproject.api.contact.Contact;
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.contact.ContactManager;
|
|
||||||
import org.briarproject.api.conversation.ConversationItem;
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
import org.briarproject.api.conversation.ConversationItem.IncomingItem;
|
||||||
import org.briarproject.api.conversation.ConversationManager;
|
|
||||||
import org.briarproject.api.crypto.CryptoExecutor;
|
|
||||||
import org.briarproject.api.db.DbException;
|
|
||||||
import org.briarproject.api.db.NoSuchContactException;
|
|
||||||
import org.briarproject.api.event.ContactConnectedEvent;
|
|
||||||
import org.briarproject.api.event.ContactDisconnectedEvent;
|
|
||||||
import org.briarproject.api.event.ContactRemovedEvent;
|
|
||||||
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
|
||||||
import org.briarproject.api.event.Event;
|
|
||||||
import org.briarproject.api.event.EventBus;
|
|
||||||
import org.briarproject.api.event.EventListener;
|
|
||||||
import org.briarproject.api.event.MessagesAckedEvent;
|
|
||||||
import org.briarproject.api.event.MessagesSentEvent;
|
|
||||||
import org.briarproject.api.messaging.PrivateMessage;
|
|
||||||
import org.briarproject.api.messaging.PrivateMessageFactory;
|
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
@@ -61,7 +43,6 @@ import java.util.Collections;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -72,10 +53,9 @@ import im.delight.android.identicons.IdenticonDrawable;
|
|||||||
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
public class ConversationActivity extends BriarActivity
|
public class ConversationActivity extends BriarActivity
|
||||||
implements EventListener, OnClickListener,
|
implements ConversationController.ConversationListener, OnClickListener,
|
||||||
ConversationAdapter.ConversationHandler,
|
ConversationAdapter.ConversationHandler,
|
||||||
ConversationAdapter.MessageUpdatedHandler {
|
ConversationAdapter.MessageUpdatedHandler {
|
||||||
|
|
||||||
@@ -85,11 +65,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManager notificationManager;
|
AndroidNotificationManager notificationManager;
|
||||||
@Inject
|
|
||||||
ConnectionRegistry connectionRegistry;
|
|
||||||
@Inject
|
|
||||||
@CryptoExecutor
|
|
||||||
protected Executor cryptoExecutor;
|
|
||||||
|
|
||||||
private ConversationAdapter adapter;
|
private ConversationAdapter adapter;
|
||||||
private CircleImageView toolbarAvatar;
|
private CircleImageView toolbarAvatar;
|
||||||
@@ -101,19 +76,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
// 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;
|
protected volatile ConversationController conversationController;
|
||||||
@Inject
|
|
||||||
protected volatile ConversationManager conversationManager;
|
|
||||||
@Inject
|
|
||||||
protected volatile EventBus eventBus;
|
|
||||||
@Inject
|
|
||||||
volatile PrivateMessageFactory privateMessageFactory;
|
|
||||||
|
|
||||||
private volatile GroupId groupId = null;
|
private volatile GroupId groupId = null;
|
||||||
private volatile ContactId contactId = null;
|
|
||||||
private volatile String contactName = null;
|
|
||||||
private volatile byte[] contactIdenticonKey = null;
|
|
||||||
private volatile boolean connected = false;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
@@ -161,6 +126,22 @@ public class ConversationActivity extends BriarActivity
|
|||||||
sendButton.setEnabled(false);
|
sendButton.setEnabled(false);
|
||||||
sendButton.setOnClickListener(this);
|
sendButton.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conversationController
|
||||||
|
.loadConversation(groupId, new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean result) {
|
||||||
|
if (result) {
|
||||||
|
displayContactDetails();
|
||||||
|
// Load the messages here to make sure we have a
|
||||||
|
// contactId
|
||||||
|
loadMessages();
|
||||||
|
} else {
|
||||||
|
// TODO Maybe an error dialog ?
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -183,16 +164,13 @@ public class ConversationActivity extends BriarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
eventBus.addListener(this);
|
|
||||||
notificationManager.blockNotification(groupId);
|
notificationManager.blockNotification(groupId);
|
||||||
notificationManager.clearPrivateMessageNotification(groupId);
|
notificationManager.clearPrivateMessageNotification(groupId);
|
||||||
loadData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
eventBus.removeListener(this);
|
|
||||||
notificationManager.unblockNotification(groupId);
|
notificationManager.unblockNotification(groupId);
|
||||||
if (isFinishing()) markMessagesRead();
|
if (isFinishing()) markMessagesRead();
|
||||||
}
|
}
|
||||||
@@ -203,8 +181,16 @@ public class ConversationActivity extends BriarActivity
|
|||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.conversation_actions, menu);
|
inflater.inflate(R.menu.conversation_actions, menu);
|
||||||
|
|
||||||
hideIntroductionActionWhenOneContact(
|
final MenuItem introduction = menu.findItem(R.id.action_introduction);
|
||||||
menu.findItem(R.id.action_introduction));
|
conversationController.shouldHideIntroductionAction(
|
||||||
|
new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean result) {
|
||||||
|
if (result) {
|
||||||
|
introduction.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
return super.onCreateOptionsMenu(menu);
|
||||||
}
|
}
|
||||||
@@ -217,6 +203,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
onBackPressed();
|
onBackPressed();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_introduction:
|
case R.id.action_introduction:
|
||||||
|
ContactId contactId = conversationController.getContactId();
|
||||||
if (contactId == null) return false;
|
if (contactId == null) return false;
|
||||||
Intent intent = new Intent(this, IntroductionActivity.class);
|
Intent intent = new Intent(this, IntroductionActivity.class);
|
||||||
intent.putExtra(IntroductionActivity.CONTACT_ID,
|
intent.putExtra(IntroductionActivity.CONTACT_ID,
|
||||||
@@ -242,46 +229,18 @@ public class ConversationActivity extends BriarActivity
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData() {
|
/**
|
||||||
runOnDbThread(new Runnable() {
|
* This should only be called after the conversation has been loaded.
|
||||||
@Override
|
*/
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (contactId == null)
|
|
||||||
contactId = conversationManager.getContactId(groupId);
|
|
||||||
if (contactName == null || contactIdenticonKey == null) {
|
|
||||||
Contact contact = contactManager.getContact(contactId);
|
|
||||||
contactName = contact.getAuthor().getName();
|
|
||||||
contactIdenticonKey =
|
|
||||||
contact.getAuthor().getId().getBytes();
|
|
||||||
}
|
|
||||||
connected = connectionRegistry.isConnected(contactId);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Loading contact took " + duration + " ms");
|
|
||||||
displayContactDetails();
|
|
||||||
// Load the messages here to make sure we have a contactId
|
|
||||||
loadMessages();
|
|
||||||
} catch (NoSuchContactException e) {
|
|
||||||
finishOnUiThread();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayContactDetails() {
|
private void displayContactDetails() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
toolbarAvatar.setImageDrawable(
|
toolbarAvatar.setImageDrawable(new IdenticonDrawable(
|
||||||
new IdenticonDrawable(contactIdenticonKey));
|
conversationController.getContactIdenticonKey()));
|
||||||
toolbarTitle.setText(contactName);
|
toolbarTitle.setText(conversationController.getContactName());
|
||||||
|
|
||||||
if (connected) {
|
if (conversationController.isConnected()) {
|
||||||
toolbarStatus.setImageDrawable(ContextCompat
|
toolbarStatus.setImageDrawable(ContextCompat
|
||||||
.getDrawable(ConversationActivity.this,
|
.getDrawable(ConversationActivity.this,
|
||||||
R.drawable.contact_online));
|
R.drawable.contact_online));
|
||||||
@@ -294,48 +253,30 @@ public class ConversationActivity extends BriarActivity
|
|||||||
toolbarStatus
|
toolbarStatus
|
||||||
.setContentDescription(getString(R.string.offline));
|
.setContentDescription(getString(R.string.offline));
|
||||||
}
|
}
|
||||||
adapter.setContactName(contactName);
|
adapter.setContactName(conversationController.getContactName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessages() {
|
private void loadMessages() {
|
||||||
runOnDbThread(new Runnable() {
|
conversationController.loadMessages(new UiResultHandler<Boolean>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void onResultUi(Boolean result) {
|
||||||
try {
|
if (result) {
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (contactId == null)
|
|
||||||
contactId = conversationManager.getContactId(groupId);
|
|
||||||
List<ConversationItem> items =
|
List<ConversationItem> items =
|
||||||
conversationManager.getMessages(contactId);
|
conversationController.getConversationItems();
|
||||||
long duration = System.currentTimeMillis() - now;
|
sendButton.setEnabled(true);
|
||||||
if (LOG.isLoggable(INFO))
|
if (items.isEmpty()) {
|
||||||
LOG.info("Loading headers took " + duration + " ms");
|
// we have no messages,
|
||||||
displayMessages(items);
|
// so let the list know to hide progress bar
|
||||||
} catch (NoSuchContactException e) {
|
list.showData();
|
||||||
finishOnUiThread();
|
} else {
|
||||||
} catch (DbException e) {
|
adapter.addAll(items);
|
||||||
if (LOG.isLoggable(WARNING))
|
// Scroll to the bottom
|
||||||
LOG.log(WARNING, e.toString(), e);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayMessages(final List<ConversationItem> items) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendButton.setEnabled(true);
|
|
||||||
if (items.isEmpty()) {
|
|
||||||
// we have no messages,
|
|
||||||
// so let the list know to hide progress bar
|
|
||||||
list.showData();
|
|
||||||
} else {
|
} else {
|
||||||
adapter.addAll(items);
|
finish();
|
||||||
// Scroll to the bottom
|
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -362,71 +303,14 @@ public class ConversationActivity extends BriarActivity
|
|||||||
if (unread.isEmpty()) return;
|
if (unread.isEmpty()) return;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Marking " + unread.size() + " messages read");
|
LOG.info("Marking " + unread.size() + " messages read");
|
||||||
markMessagesRead(Collections.unmodifiableList(unread));
|
conversationController.markMessagesRead(
|
||||||
}
|
Collections.unmodifiableList(unread),
|
||||||
|
new UiResultHandler<Boolean>(this) {
|
||||||
private void markMessagesRead(final Collection<ConversationItem> unread) {
|
@Override
|
||||||
runOnDbThread(new Runnable() {
|
public void onResultUi(Boolean result) {
|
||||||
@Override
|
// TODO something?
|
||||||
public void run() {
|
}
|
||||||
try {
|
});
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
for (ConversationItem item : unread)
|
|
||||||
conversationManager.setReadFlag(contactId, item, true);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Marking read took " + duration + " ms");
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void eventOccurred(Event e) {
|
|
||||||
if (e instanceof ContactRemovedEvent) {
|
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact removed");
|
|
||||||
finishOnUiThread();
|
|
||||||
}
|
|
||||||
} else if (e instanceof ConversationItemReceivedEvent) {
|
|
||||||
ConversationItemReceivedEvent event =
|
|
||||||
(ConversationItemReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Message received, adding");
|
|
||||||
addConversationItem(event.getItem());
|
|
||||||
markMessageReadIfNew(event.getItem());
|
|
||||||
}
|
|
||||||
} else if (e instanceof MessagesSentEvent) {
|
|
||||||
MessagesSentEvent m = (MessagesSentEvent) e;
|
|
||||||
if (m.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Messages sent");
|
|
||||||
markMessages(m.getMessageIds(), true, false);
|
|
||||||
}
|
|
||||||
} else if (e instanceof MessagesAckedEvent) {
|
|
||||||
MessagesAckedEvent m = (MessagesAckedEvent) e;
|
|
||||||
if (m.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Messages acked");
|
|
||||||
markMessages(m.getMessageIds(), true, true);
|
|
||||||
}
|
|
||||||
} else if (e instanceof ContactConnectedEvent) {
|
|
||||||
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact connected");
|
|
||||||
connected = true;
|
|
||||||
displayContactDetails();
|
|
||||||
}
|
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
|
||||||
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact disconnected");
|
|
||||||
connected = false;
|
|
||||||
displayContactDetails();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markMessageReadIfNew(final ConversationItem item) {
|
private void markMessageReadIfNew(final ConversationItem item) {
|
||||||
@@ -438,32 +322,19 @@ public class ConversationActivity extends BriarActivity
|
|||||||
// Mark the message read if it's the newest message
|
// Mark the message read if it's the newest message
|
||||||
long lastMsgTime = last.getTime();
|
long lastMsgTime = last.getTime();
|
||||||
long newMsgTime = item.getTime();
|
long newMsgTime = item.getTime();
|
||||||
if (newMsgTime > lastMsgTime) markNewMessageRead(item);
|
if (newMsgTime > lastMsgTime)
|
||||||
else loadMessages();
|
conversationController.markNewMessageRead(item);
|
||||||
} else {
|
} else {
|
||||||
// mark the message as read as well if it is the first one
|
// mark the message as read as well if it is the first one
|
||||||
markNewMessageRead(item);
|
conversationController.markNewMessageRead(item);
|
||||||
}
|
}
|
||||||
|
loadMessages();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markNewMessageRead(final ConversationItem item) {
|
@Override
|
||||||
runOnDbThread(new Runnable() {
|
public void markMessages(final Collection<MessageId> messageIds,
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
conversationManager.setReadFlag(contactId, item, true);
|
|
||||||
loadMessages();
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markMessages(final Collection<MessageId> messageIds,
|
|
||||||
final boolean sent, final boolean seen) {
|
final boolean sent, final boolean seen) {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -483,6 +354,12 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageReceived(ConversationItem item) {
|
||||||
|
addConversationItem(item);
|
||||||
|
markMessageReadIfNew(item);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
markMessagesRead();
|
markMessagesRead();
|
||||||
@@ -501,37 +378,14 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createMessage(final byte[] body, final long timestamp) {
|
private void createMessage(final byte[] body, final long timestamp) {
|
||||||
cryptoExecutor.execute(new Runnable() {
|
conversationController.createMessage(body, timestamp,
|
||||||
@Override
|
new UiResultHandler<ConversationItem>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
try {
|
public void onResultUi(ConversationItem item) {
|
||||||
storeMessage(privateMessageFactory
|
if (item != null)
|
||||||
.createPrivateMessage(groupId, timestamp, null,
|
addConversationItem(item);
|
||||||
"text/plain", body), body);
|
}
|
||||||
} catch (FormatException e) {
|
});
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMessage(final PrivateMessage m, final byte[] body) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
ConversationItem item = conversationManager.addLocalMessage(m, body);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Storing message took " + duration + " ms");
|
|
||||||
addConversationItem(item);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askToRemoveContact() {
|
private void askToRemoveContact() {
|
||||||
@@ -553,82 +407,42 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeContact() {
|
private void removeContact() {
|
||||||
runOnDbThread(new Runnable() {
|
conversationController
|
||||||
@Override
|
.removeContact(new UiResultHandler<Boolean>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
try {
|
public void onResultUi(Boolean result) {
|
||||||
// make sure contactId is initialised
|
if (result) {
|
||||||
if (contactId == null)
|
String deleted =
|
||||||
contactId = conversationManager.getContactId(groupId);
|
getString(R.string.contact_deleted_toast);
|
||||||
// remove contact with that ID
|
Toast.makeText(ConversationActivity.this, deleted,
|
||||||
contactManager.removeContact(contactId);
|
LENGTH_SHORT)
|
||||||
} catch (DbException e) {
|
.show();
|
||||||
if (LOG.isLoggable(WARNING))
|
finish();
|
||||||
LOG.log(WARNING, e.toString(), e);
|
} else {
|
||||||
} finally {
|
String failed = getString(
|
||||||
finishAfterContactRemoved();
|
R.string.contact_deletion_failed_toast);
|
||||||
}
|
Toast.makeText(ConversationActivity.this, failed,
|
||||||
}
|
LENGTH_SHORT).show();
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void finishAfterContactRemoved() {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String deleted = getString(R.string.contact_deleted_toast);
|
|
||||||
Toast.makeText(ConversationActivity.this, deleted, LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideIntroductionActionWhenOneContact(final MenuItem item) {
|
|
||||||
runOnDbThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (contactManager.getActiveContacts().size() < 2) {
|
|
||||||
hideIntroductionAction(item);
|
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
});
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideIntroductionAction(final MenuItem item) {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
item.setVisible(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void respondToItem(final ConversationItem item,
|
public void respondToItem(ConversationItem item, boolean accept) {
|
||||||
final boolean accept) {
|
long minTimestamp = getMinTimestampForNewMessage();
|
||||||
runOnDbThread(new Runnable() {
|
conversationController.respondToItem(item, accept, minTimestamp,
|
||||||
@Override
|
new UiResultHandler<Boolean>(this) {
|
||||||
public void run() {
|
@Override
|
||||||
long timestamp = System.currentTimeMillis();
|
public void onResultUi(Boolean result) {
|
||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
if (result) {
|
||||||
try {
|
loadMessages();
|
||||||
conversationManager
|
} else {
|
||||||
.respondToItem(contactId, item, accept, timestamp);
|
// TODO decide how to make this type-agnostic
|
||||||
loadMessages();
|
introductionResponseError();
|
||||||
} catch (DbException | FormatException e) {
|
}
|
||||||
// TODO decide how to make this type-agnostic
|
}
|
||||||
introductionResponseError();
|
});
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void introductionResponseError() {
|
private void introductionResponseError() {
|
||||||
@@ -653,4 +467,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contactUpdated() {
|
||||||
|
displayContactDetails();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import org.briarproject.android.controller.ActivityLifecycleController;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConversationController extends ActivityLifecycleController {
|
||||||
|
|
||||||
|
void loadConversation(GroupId groupId,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void loadMessages(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void createMessage(byte[] body, long timestamp,
|
||||||
|
UiResultHandler<ConversationItem> resultHandler);
|
||||||
|
|
||||||
|
ContactId getContactId();
|
||||||
|
|
||||||
|
String getContactName();
|
||||||
|
|
||||||
|
byte[] getContactIdenticonKey();
|
||||||
|
|
||||||
|
List<ConversationItem> getConversationItems();
|
||||||
|
|
||||||
|
boolean isConnected();
|
||||||
|
|
||||||
|
void markMessagesRead(Collection<ConversationItem> unread,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void markNewMessageRead(ConversationItem item);
|
||||||
|
|
||||||
|
void removeContact(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void respondToItem(ConversationItem item, boolean accept, long minTimestamp,
|
||||||
|
UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void shouldHideIntroductionAction(UiResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
interface ConversationListener {
|
||||||
|
void contactUpdated();
|
||||||
|
|
||||||
|
void markMessages(Collection<MessageId> messageIds, boolean sent,
|
||||||
|
boolean seen);
|
||||||
|
|
||||||
|
void messageReceived(ConversationItem item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,408 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
|
||||||
|
import org.briarproject.android.controller.DbControllerImpl;
|
||||||
|
import org.briarproject.android.controller.handler.UiResultHandler;
|
||||||
|
import org.briarproject.api.FormatException;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.contact.ContactManager;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.api.crypto.CryptoExecutor;
|
||||||
|
import org.briarproject.api.db.DbException;
|
||||||
|
import org.briarproject.api.db.NoSuchContactException;
|
||||||
|
import org.briarproject.api.event.ContactConnectedEvent;
|
||||||
|
import org.briarproject.api.event.ContactDisconnectedEvent;
|
||||||
|
import org.briarproject.api.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.api.event.ConversationItemReceivedEvent;
|
||||||
|
import org.briarproject.api.event.Event;
|
||||||
|
import org.briarproject.api.event.EventBus;
|
||||||
|
import org.briarproject.api.event.EventListener;
|
||||||
|
import org.briarproject.api.event.MessagesAckedEvent;
|
||||||
|
import org.briarproject.api.event.MessagesSentEvent;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessage;
|
||||||
|
import org.briarproject.api.messaging.PrivateMessageFactory;
|
||||||
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class ConversationControllerImpl extends DbControllerImpl
|
||||||
|
implements ConversationController, EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(ConversationControllerImpl.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected Activity activity;
|
||||||
|
@Inject
|
||||||
|
protected ConnectionRegistry connectionRegistry;
|
||||||
|
@Inject
|
||||||
|
@CryptoExecutor
|
||||||
|
protected Executor cryptoExecutor;
|
||||||
|
|
||||||
|
// Fields that are accessed from background threads must be volatile
|
||||||
|
@Inject
|
||||||
|
protected volatile ContactManager contactManager;
|
||||||
|
@Inject
|
||||||
|
protected volatile ConversationManager conversationManager;
|
||||||
|
@Inject
|
||||||
|
protected volatile EventBus eventBus;
|
||||||
|
@Inject
|
||||||
|
protected volatile PrivateMessageFactory privateMessageFactory;
|
||||||
|
@Inject
|
||||||
|
protected ConversationPersistentData data;
|
||||||
|
|
||||||
|
private ConversationListener listener;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConversationControllerImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreate() {
|
||||||
|
if (activity instanceof ConversationListener) {
|
||||||
|
listener = (ConversationListener) activity;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"An activity that injects the ConversationController " +
|
||||||
|
"must implement the ConversationListener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResume() {
|
||||||
|
eventBus.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityPause() {
|
||||||
|
eventBus.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityDestroy() {
|
||||||
|
if (activity.isFinishing()) {
|
||||||
|
data.clearAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadConversation(final GroupId groupId,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (data.getGroupId() == null ||
|
||||||
|
!data.getGroupId().equals(groupId)) {
|
||||||
|
data.setGroupId(groupId);
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
ContactId contactId =
|
||||||
|
conversationManager.getContactId(groupId);
|
||||||
|
data.setContact(contactManager.getContact(contactId));
|
||||||
|
data.setConnected(
|
||||||
|
connectionRegistry.isConnected(contactId));
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(
|
||||||
|
"Loading contact took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (NoSuchContactException e) {
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMessages(final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
data.addConversationItems(
|
||||||
|
conversationManager
|
||||||
|
.getMessages(getContactId()));
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info(
|
||||||
|
"Loading headers took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (NoSuchContactException e) {
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMessage(final byte[] body, final long timestamp,
|
||||||
|
final UiResultHandler<ConversationItem> resultHandler) {
|
||||||
|
cryptoExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
PrivateMessage m = privateMessageFactory
|
||||||
|
.createPrivateMessage(data.getGroupId(), timestamp,
|
||||||
|
null, "text/plain", body);
|
||||||
|
storeMessage(m, body, resultHandler);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
// TODO why was this being thrown?
|
||||||
|
//throw new RuntimeException(e);
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeMessage(final PrivateMessage m, final byte[] body,
|
||||||
|
final UiResultHandler<ConversationItem> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
ConversationItem item =
|
||||||
|
conversationManager.addLocalMessage(m, body);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Storing message took " + duration + " ms");
|
||||||
|
resultHandler.onResult(item);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return data.getContact() == null ? null : data.getContact().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContactName() {
|
||||||
|
return data.getContact() == null ? null :
|
||||||
|
data.getContact().getAuthor().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getContactIdenticonKey() {
|
||||||
|
return data.getContact() == null ? null :
|
||||||
|
data.getContact().getAuthor().getId().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ConversationItem> getConversationItems() {
|
||||||
|
return data.getConversationItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return data.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markMessagesRead(final Collection<ConversationItem> unread,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
for (ConversationItem item : unread)
|
||||||
|
conversationManager
|
||||||
|
.setReadFlag(getContactId(), item, true);
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Marking read took " + duration + " ms");
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markNewMessageRead(final ConversationItem item) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
conversationManager
|
||||||
|
.setReadFlag(getContactId(), item, true);
|
||||||
|
}
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeContact(final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (getContactId() != null) {
|
||||||
|
contactManager.removeContact(getContactId());
|
||||||
|
}
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void respondToItem(final ConversationItem item, final boolean accept,
|
||||||
|
final long minTimestamp,
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
timestamp = Math.max(timestamp, minTimestamp);
|
||||||
|
try {
|
||||||
|
conversationManager
|
||||||
|
.respondToItem(getContactId(), item, accept,
|
||||||
|
timestamp);
|
||||||
|
resultHandler.onResult(true);
|
||||||
|
} catch (DbException | FormatException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shouldHideIntroductionAction(
|
||||||
|
final UiResultHandler<Boolean> resultHandler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
resultHandler.onResult(
|
||||||
|
contactManager.getActiveContacts().size() < 2);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
resultHandler.onResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof ContactRemovedEvent) {
|
||||||
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact removed");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ConversationItemReceivedEvent) {
|
||||||
|
final ConversationItemReceivedEvent event =
|
||||||
|
(ConversationItemReceivedEvent) e;
|
||||||
|
if (event.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Message received, adding");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.messageReceived(event.getItem());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof MessagesSentEvent) {
|
||||||
|
final MessagesSentEvent m = (MessagesSentEvent) e;
|
||||||
|
if (m.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Messages sent");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.markMessages(m.getMessageIds(), true, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof MessagesAckedEvent) {
|
||||||
|
final MessagesAckedEvent m = (MessagesAckedEvent) e;
|
||||||
|
if (m.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Messages acked");
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.markMessages(m.getMessageIds(), true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ContactConnectedEvent) {
|
||||||
|
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact connected");
|
||||||
|
data.setConnected(true);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.contactUpdated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
|
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
||||||
|
if (c.getContactId().equals(getContactId())) {
|
||||||
|
LOG.info("Contact disconnected");
|
||||||
|
data.setConnected(false);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
listener.contactUpdated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.briarproject.android.contact;
|
||||||
|
|
||||||
|
import org.briarproject.api.contact.Contact;
|
||||||
|
import org.briarproject.api.conversation.ConversationItem;
|
||||||
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a singleton that defines the data that should persist, i.e.
|
||||||
|
* still be present in memory after activity restarts. This class is not thread
|
||||||
|
* safe.
|
||||||
|
*/
|
||||||
|
public class ConversationPersistentData {
|
||||||
|
|
||||||
|
private volatile GroupId groupId;
|
||||||
|
private volatile Contact contact;
|
||||||
|
private volatile boolean connected;
|
||||||
|
private volatile List<ConversationItem> items = new ArrayList<>();
|
||||||
|
|
||||||
|
public void clearAll() {
|
||||||
|
groupId = null;
|
||||||
|
contact = null;
|
||||||
|
connected = false;
|
||||||
|
items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupId getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupId(GroupId groupId) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contact getContact() {
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContact(Contact contact) {
|
||||||
|
this.contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnected(boolean connected) {
|
||||||
|
this.connected = connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConversationItems(Collection<ConversationItem> items) {
|
||||||
|
this.items.addAll(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConversationItem> getConversationItems() {
|
||||||
|
return Collections.unmodifiableList(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user