aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/services
diff options
context:
space:
mode:
authorlookshe <github@lookshe.org>2015-01-03 23:19:05 +0100
committerlookshe <github@lookshe.org>2015-01-03 23:19:05 +0100
commit95e2a539517c27b3235acd582f17968c8e301e81 (patch)
tree213bbeed798751e949376d85f4d7d0bd30c5fbfa /src/main/java/eu/siacs/conversations/services
parent48717dd7d37c066ab626fc626a2ced626ef21d42 (diff)
parent4f4eff2353f4e359b5582c8e808a4e88631c3e74 (diff)
Merge branch 'master' of ssh://git.fucktheforce.de/conversations
Conflicts: src/main/java/eu/siacs/conversations/Config.java src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java src/main/java/eu/siacs/conversations/utils/UIHelper.java
Diffstat (limited to 'src/main/java/eu/siacs/conversations/services')
-rw-r--r--src/main/java/eu/siacs/conversations/services/MessageArchiveService.java366
-rw-r--r--src/main/java/eu/siacs/conversations/services/NotificationService.java202
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java648
3 files changed, 851 insertions, 365 deletions
diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
new file mode 100644
index 00000000..82111243
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
@@ -0,0 +1,366 @@
+package eu.siacs.conversations.services;
+
+import android.util.Log;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.generator.AbstractGenerator;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
+import eu.siacs.conversations.xmpp.OnIqPacketReceived;
+import eu.siacs.conversations.xmpp.jid.Jid;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
+public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
+
+ private final XmppConnectionService mXmppConnectionService;
+
+ private final HashSet<Query> queries = new HashSet<Query>();
+ private final ArrayList<Query> pendingQueries = new ArrayList<Query>();
+
+ public enum PagingOrder {
+ NORMAL,
+ REVERSE
+ };
+
+ public MessageArchiveService(final XmppConnectionService service) {
+ this.mXmppConnectionService = service;
+ }
+
+ public void catchup(final Account account) {
+ long startCatchup = getLastMessageTransmitted(account);
+ long endCatchup = account.getXmppConnection().getLastSessionEstablished();
+ if (startCatchup == 0) {
+ return;
+ } else if (endCatchup - startCatchup >= Config.MAM_MAX_CATCHUP) {
+ startCatchup = endCatchup - Config.MAM_MAX_CATCHUP;
+ List<Conversation> conversations = mXmppConnectionService.getConversations();
+ for (Conversation conversation : conversations) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE && conversation.getAccount() == account && startCatchup > conversation.getLastMessageTransmitted()) {
+ this.query(conversation,startCatchup);
+ }
+ }
+ }
+ final Query query = new Query(account, startCatchup, endCatchup);
+ this.queries.add(query);
+ this.execute(query);
+ }
+
+ private long getLastMessageTransmitted(final Account account) {
+ long timestamp = 0;
+ for(final Conversation conversation : mXmppConnectionService.getConversations()) {
+ if (conversation.getAccount() == account) {
+ long tmp = conversation.getLastMessageTransmitted();
+ if (tmp > timestamp) {
+ timestamp = tmp;
+ }
+ }
+ }
+ return timestamp;
+ }
+
+ public Query query(final Conversation conversation) {
+ return query(conversation,conversation.getAccount().getXmppConnection().getLastSessionEstablished());
+ }
+
+ public Query query(final Conversation conversation, long end) {
+ return this.query(conversation,conversation.getLastMessageTransmitted(),end);
+ }
+
+ public Query query(Conversation conversation, long start, long end) {
+ synchronized (this.queries) {
+ if (start > end) {
+ return null;
+ }
+ final Query query = new Query(conversation, start, end,PagingOrder.REVERSE);
+ this.queries.add(query);
+ this.execute(query);
+ return query;
+ }
+ }
+
+ public void executePendingQueries(final Account account) {
+ List<Query> pending = new ArrayList<>();
+ synchronized(this.pendingQueries) {
+ for(Iterator<Query> iterator = this.pendingQueries.iterator(); iterator.hasNext();) {
+ Query query = iterator.next();
+ if (query.getAccount() == account) {
+ pending.add(query);
+ iterator.remove();
+ }
+ }
+ }
+ for(Query query : pending) {
+ this.execute(query);
+ }
+ }
+
+ private void execute(final Query query) {
+ final Account account= query.getAccount();
+ if (account.getStatus() == Account.State.ONLINE) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": running mam query " + query.toString());
+ IqPacket packet = this.mXmppConnectionService.getIqGenerator().queryMessageArchiveManagement(query);
+ this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE_ERROR) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString());
+ finalizeQuery(query);
+ }
+ }
+ });
+ } else {
+ synchronized (this.pendingQueries) {
+ this.pendingQueries.add(query);
+ }
+ }
+ }
+
+ private void finalizeQuery(Query query) {
+ synchronized (this.queries) {
+ this.queries.remove(query);
+ }
+ final Conversation conversation = query.getConversation();
+ if (conversation != null) {
+ conversation.sort();
+ if (conversation.setLastMessageTransmitted(query.getEnd())) {
+ this.mXmppConnectionService.databaseBackend.updateConversation(conversation);
+ }
+ conversation.setHasMessagesLeftOnServer(query.getMessageCount() > 0);
+ if (query.hasCallback()) {
+ query.callback();
+ } else {
+ this.mXmppConnectionService.updateConversationUi();
+ }
+ } else {
+ for(Conversation tmp : this.mXmppConnectionService.getConversations()) {
+ if (tmp.getAccount() == query.getAccount()) {
+ tmp.sort();
+ if (tmp.setLastMessageTransmitted(query.getEnd())) {
+ this.mXmppConnectionService.databaseBackend.updateConversation(tmp);
+ }
+ }
+ }
+ }
+ }
+
+ public boolean queryInProgress(Conversation conversation, XmppConnectionService.OnMoreMessagesLoaded callback) {
+ synchronized (this.queries) {
+ for(Query query : queries) {
+ if (query.conversation == conversation) {
+ if (!query.hasCallback() && callback != null) {
+ query.setCallback(callback);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public void processFin(Element fin) {
+ if (fin == null) {
+ return;
+ }
+ Query query = findQuery(fin.getAttribute("queryid"));
+ if (query == null) {
+ return;
+ }
+ boolean complete = fin.getAttributeAsBoolean("complete");
+ Element set = fin.findChild("set","http://jabber.org/protocol/rsm");
+ Element last = set == null ? null : set.findChild("last");
+ Element first = set == null ? null : set.findChild("first");
+ Element relevant = query.getPagingOrder() == PagingOrder.NORMAL ? last : first;
+ boolean abort = (query.getStart() == 0 && query.getTotalCount() >= Config.PAGE_SIZE) || query.getTotalCount() >= Config.MAM_MAX_MESSAGES;
+ if (complete || relevant == null || abort) {
+ this.finalizeQuery(query);
+ Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages");
+ } else {
+ final Query nextQuery;
+ if (query.getPagingOrder() == PagingOrder.NORMAL) {
+ nextQuery = query.next(last == null ? null : last.getContent());
+ } else {
+ nextQuery = query.prev(first == null ? null : first.getContent());
+ }
+ this.execute(nextQuery);
+ this.finalizeQuery(query);
+ synchronized (this.queries) {
+ this.queries.remove(query);
+ this.queries.add(nextQuery);
+ }
+ }
+ }
+
+ public Query findQuery(String id) {
+ if (id == null) {
+ return null;
+ }
+ synchronized (this.queries) {
+ for(Query query : this.queries) {
+ if (query.getQueryId().equals(id)) {
+ return query;
+ }
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public void onAdvancedStreamFeaturesAvailable(Account account) {
+ if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().mam()) {
+ this.catchup(account);
+ }
+ }
+
+ public class Query {
+ private int totalCount = 0;
+ private int messageCount = 0;
+ private long start;
+ private long end;
+ private Jid with = null;
+ private String queryId;
+ private String reference = null;
+ private Account account;
+ private Conversation conversation;
+ private PagingOrder pagingOrder = PagingOrder.NORMAL;
+ private XmppConnectionService.OnMoreMessagesLoaded callback = null;
+
+
+ public Query(Conversation conversation, long start, long end) {
+ this(conversation.getAccount(), start, end);
+ this.conversation = conversation;
+ this.with = conversation.getJid().toBareJid();
+ }
+
+ public Query(Conversation conversation, long start, long end, PagingOrder order) {
+ this(conversation,start,end);
+ this.pagingOrder = order;
+ }
+
+ public Query(Account account, long start, long end) {
+ this.account = account;
+ this.start = start;
+ this.end = end;
+ this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32);
+ }
+
+ private Query page(String reference) {
+ Query query = new Query(this.account,this.start,this.end);
+ query.reference = reference;
+ query.conversation = conversation;
+ query.with = with;
+ query.totalCount = totalCount;
+ query.callback = callback;
+ return query;
+ }
+
+ public Query next(String reference) {
+ Query query = page(reference);
+ query.pagingOrder = PagingOrder.NORMAL;
+ return query;
+ }
+
+ public Query prev(String reference) {
+ Query query = page(reference);
+ query.pagingOrder = PagingOrder.REVERSE;
+ return query;
+ }
+
+ public String getReference() {
+ return reference;
+ }
+
+ public PagingOrder getPagingOrder() {
+ return this.pagingOrder;
+ }
+
+ public String getQueryId() {
+ return queryId;
+ }
+
+ public Jid getWith() {
+ return with;
+ }
+
+ public long getStart() {
+ return start;
+ }
+
+ public void setCallback(XmppConnectionService.OnMoreMessagesLoaded callback) {
+ this.callback = callback;
+ }
+
+ public void callback() {
+ if (this.callback != null) {
+ this.callback.onMoreMessagesLoaded(messageCount,conversation);
+ if (messageCount == 0) {
+ this.callback.informUser(R.string.no_more_history_on_server);
+ }
+ }
+ }
+
+ public long getEnd() {
+ return end;
+ }
+
+ public Conversation getConversation() {
+ return conversation;
+ }
+
+ public Account getAccount() {
+ return this.account;
+ }
+
+ public void incrementTotalCount() {
+ this.totalCount++;
+ }
+
+ public void incrementMessageCount() {
+ this.messageCount++;
+ }
+
+ public int getTotalCount() {
+ return this.totalCount;
+ }
+
+ public int getMessageCount() {
+ return this.messageCount;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("with=");
+ if (this.with==null) {
+ builder.append("*");
+ } else {
+ builder.append(with.toString());
+ }
+ builder.append(", start=");
+ builder.append(AbstractGenerator.getTimestamp(this.start));
+ builder.append(", end=");
+ builder.append(AbstractGenerator.getTimestamp(this.end));
+ if (this.reference!=null) {
+ if (this.pagingOrder == PagingOrder.NORMAL) {
+ builder.append(", after=");
+ } else {
+ builder.append(", before=");
+ }
+ builder.append(this.reference);
+ }
+ return builder.toString();
+ }
+
+ public boolean hasCallback() {
+ return this.callback != null;
+ }
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index f649f9d4..a30cf2f1 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -16,9 +16,11 @@ import android.support.v4.app.NotificationCompat.Builder;
import android.support.v4.app.TaskStackBuilder;
import android.text.Html;
import android.util.DisplayMetrics;
+import android.util.Log;
import java.io.FileNotFoundException;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.regex.Matcher;
@@ -33,16 +35,17 @@ import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.ui.ManageAccountActivity;
+import eu.siacs.conversations.ui.TimePreference;
public class NotificationService {
private XmppConnectionService mXmppConnectionService;
- private LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<String, ArrayList<Message>>();
+ private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>();
- public static int NOTIFICATION_ID = 0x2342;
- public static int FOREGROUND_NOTIFICATION_ID = 0x8899;
- public static int ERROR_NOTIFICATION_ID = 0x5678;
+ public static final int NOTIFICATION_ID = 0x2342;
+ public static final int FOREGROUND_NOTIFICATION_ID = 0x8899;
+ public static final int ERROR_NOTIFICATION_ID = 0x5678;
private Conversation mOpenConversation;
private boolean mIsInForeground;
@@ -52,46 +55,61 @@ public class NotificationService {
this.mXmppConnectionService = service;
}
- public boolean notify(Message message) {
+ public boolean notify(final Message message) {
return (message.getStatus() == Message.STATUS_RECEIVED)
- && notificationsEnabled()
- && !message.getConversation().isMuted()
- && (message.getConversation().getMode() == Conversation.MODE_SINGLE
+ && notificationsEnabled()
+ && !message.getConversation().isMuted()
+ && (message.getConversation().getMode() == Conversation.MODE_SINGLE
|| conferenceNotificationsEnabled()
|| wasHighlightedOrPrivate(message)
- );
+ );
}
public boolean notificationsEnabled() {
return mXmppConnectionService.getPreferences().getBoolean("show_notification", true);
}
+ public boolean isQuietHours() {
+ if (!mXmppConnectionService.getPreferences().getBoolean("enable_quiet_hours", false)) {
+ return false;
+ }
+ final long startTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY;
+ final long endTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY;
+ final long nowTime = Calendar.getInstance().getTimeInMillis() % Config.MILLISECONDS_IN_DAY;
+
+ if (endTime < startTime) {
+ return nowTime > startTime || nowTime < endTime;
+ } else {
+ return nowTime > startTime && nowTime < endTime;
+ }
+ }
+
public boolean conferenceNotificationsEnabled() {
return mXmppConnectionService.getPreferences().getBoolean("always_notify_in_conference", false);
}
- public void push(Message message) {
+ public void push(final Message message) {
if (!notify(message)) {
return;
}
- PowerManager pm = (PowerManager) mXmppConnectionService
- .getSystemService(Context.POWER_SERVICE);
- boolean isScreenOn = pm.isScreenOn();
+ final PowerManager pm = (PowerManager) mXmppConnectionService
+ .getSystemService(Context.POWER_SERVICE);
+ final boolean isScreenOn = pm.isScreenOn();
if (this.mIsInForeground && isScreenOn
&& this.mOpenConversation == message.getConversation()) {
return;
- }
+ }
synchronized (notifications) {
- String conversationUuid = message.getConversationUuid();
+ final String conversationUuid = message.getConversationUuid();
if (notifications.containsKey(conversationUuid)) {
notifications.get(conversationUuid).add(message);
} else {
- ArrayList<Message> mList = new ArrayList<Message>();
+ final ArrayList<Message> mList = new ArrayList<>();
mList.add(message);
notifications.put(conversationUuid, mList);
}
- Account account = message.getConversation().getAccount();
+ final Account account = message.getConversation().getAccount();
updateNotification((!(this.mIsInForeground && this.mOpenConversation == null) || !isScreenOn)
&& !account.inGracePeriod()
&& !this.inMiniGracePeriod(account));
@@ -106,21 +124,20 @@ public class NotificationService {
}
}
- public void clear(Conversation conversation) {
+ public void clear(final Conversation conversation) {
synchronized (notifications) {
notifications.remove(conversation.getUuid());
updateNotification(false);
}
}
- private void updateNotification(boolean notify) {
- NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
- .getSystemService(Context.NOTIFICATION_SERVICE);
- SharedPreferences preferences = mXmppConnectionService.getPreferences();
+ private void updateNotification(final boolean notify) {
+ final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ final SharedPreferences preferences = mXmppConnectionService.getPreferences();
- String ringtone = preferences.getString("notification_ringtone", null);
- boolean vibrate = preferences.getBoolean("vibrate_on_notification",
- true);
+ final String ringtone = preferences.getString("notification_ringtone", null);
+ final boolean vibrate = preferences.getBoolean("vibrate_on_notification", true);
if (notifications.size() == 0) {
notificationManager.cancel(NOTIFICATION_ID);
@@ -128,16 +145,16 @@ public class NotificationService {
if (notify) {
this.markLastNotification();
}
- Builder mBuilder;
+ final Builder mBuilder;
if (notifications.size() == 1) {
mBuilder = buildSingleConversations(notify);
} else {
mBuilder = buildMultipleConversation();
}
- if (notify) {
+ if (notify && !isQuietHours()) {
if (vibrate) {
- int dat = 70;
- long[] pattern = {0, 3 * dat, dat, dat};
+ final int dat = 70;
+ final long[] pattern = {0, 3 * dat, dat, dat};
mBuilder.setVibrate(pattern);
}
if (ringtone != null) {
@@ -147,27 +164,27 @@ public class NotificationService {
mBuilder.setSmallIcon(R.drawable.ic_notification);
mBuilder.setDeleteIntent(createDeleteIntent());
mBuilder.setLights(0xffffffff, 2000, 4000);
- Notification notification = mBuilder.build();
+ final Notification notification = mBuilder.build();
notificationManager.notify(NOTIFICATION_ID, notification);
}
}
private Builder buildMultipleConversation() {
- Builder mBuilder = new NotificationCompat.Builder(
+ final Builder mBuilder = new NotificationCompat.Builder(
mXmppConnectionService);
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
style.setBigContentTitle(notifications.size()
+ " "
+ mXmppConnectionService
.getString(R.string.unread_conversations));
- StringBuilder names = new StringBuilder();
+ final StringBuilder names = new StringBuilder();
Conversation conversation = null;
for (ArrayList<Message> messages : notifications.values()) {
if (messages.size() > 0) {
conversation = messages.get(0).getConversation();
String name = conversation.getName();
style.addLine(Html.fromHtml("<b>" + name + "</b> "
- + getReadableBody(messages.get(0))));
+ + getReadableBody(messages.get(0))));
names.append(name);
names.append(", ");
}
@@ -183,46 +200,45 @@ public class NotificationService {
mBuilder.setStyle(style);
if (conversation != null) {
mBuilder.setContentIntent(createContentIntent(conversation
- .getUuid()));
+ .getUuid()));
}
return mBuilder;
}
- private Builder buildSingleConversations(boolean notify) {
- Builder mBuilder = new NotificationCompat.Builder(
+ private Builder buildSingleConversations(final boolean notify) {
+ final Builder mBuilder = new NotificationCompat.Builder(
mXmppConnectionService);
- ArrayList<Message> messages = notifications.values().iterator().next();
+ final ArrayList<Message> messages = notifications.values().iterator().next();
if (messages.size() >= 1) {
- Conversation conversation = messages.get(0).getConversation();
+ final Conversation conversation = messages.get(0).getConversation();
mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
.get(conversation, getPixel(64)));
mBuilder.setContentTitle(conversation.getName());
- Message message;
+ final Message message;
if ((message = getImage(messages)) != null) {
modifyForImage(mBuilder, message, messages, notify);
} else {
modifyForTextOnly(mBuilder, messages, notify);
}
mBuilder.setContentIntent(createContentIntent(conversation
- .getUuid()));
+ .getUuid()));
}
return mBuilder;
-
}
- private void modifyForImage(Builder builder, Message message,
- ArrayList<Message> messages, boolean notify) {
+ private void modifyForImage(final Builder builder, final Message message,
+ final ArrayList<Message> messages, final boolean notify) {
try {
- Bitmap bitmap = mXmppConnectionService.getFileBackend()
- .getThumbnail(message, getPixel(288), false);
- ArrayList<Message> tmp = new ArrayList<Message>();
- for (Message msg : messages) {
+ final Bitmap bitmap = mXmppConnectionService.getFileBackend()
+ .getThumbnail(message, getPixel(288), false);
+ final ArrayList<Message> tmp = new ArrayList<>();
+ for (final Message msg : messages) {
if (msg.getType() == Message.TYPE_TEXT
&& msg.getDownloadable() == null) {
tmp.add(msg);
- }
+ }
}
- BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
+ final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
bigPictureStyle.bigPicture(bitmap);
if (tmp.size() > 0) {
bigPictureStyle.setSummaryText(getMergedBodies(tmp));
@@ -231,13 +247,13 @@ public class NotificationService {
builder.setContentText(mXmppConnectionService.getString(R.string.image_file));
}
builder.setStyle(bigPictureStyle);
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException e) {
modifyForTextOnly(builder, messages, notify);
}
}
- private void modifyForTextOnly(Builder builder,
- ArrayList<Message> messages, boolean notify) {
+ private void modifyForTextOnly(final Builder builder,
+ final ArrayList<Message> messages, final boolean notify) {
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(getMergedBodies(messages)));
builder.setContentText(getReadableBody(messages.get(0)));
@@ -246,19 +262,19 @@ public class NotificationService {
}
}
- private Message getImage(ArrayList<Message> messages) {
- for (Message message : messages) {
+ private Message getImage(final ArrayList<Message> messages) {
+ for (final Message message : messages) {
if (message.getType() == Message.TYPE_IMAGE
&& message.getDownloadable() == null
&& message.getEncryption() != Message.ENCRYPTION_PGP) {
return message;
- }
+ }
}
return null;
}
- private String getMergedBodies(ArrayList<Message> messages) {
- StringBuilder text = new StringBuilder();
+ private String getMergedBodies(final ArrayList<Message> messages) {
+ final StringBuilder text = new StringBuilder();
for (int i = 0; i < messages.size(); ++i) {
text.append(getReadableBody(messages.get(i)));
if (i != messages.size() - 1) {
@@ -268,10 +284,10 @@ public class NotificationService {
return text.toString();
}
- private String getReadableBody(Message message) {
+ private String getReadableBody(final Message message) {
if (message.getDownloadable() != null
&& (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message
- .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) {
+ .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) {
if (message.getType() == Message.TYPE_FILE) {
return mXmppConnectionService.getString(R.string.file_offered_for_download);
} else {
@@ -283,27 +299,27 @@ public class NotificationService {
R.string.encrypted_message_received).toString();
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
return mXmppConnectionService.getText(R.string.decryption_failed)
- .toString();
+ .toString();
} else if (message.getType() == Message.TYPE_FILE) {
DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message);
return mXmppConnectionService.getString(R.string.file,file.getMimeType());
} else if (message.getType() == Message.TYPE_IMAGE) {
return mXmppConnectionService.getText(R.string.image_file)
- .toString();
+ .toString();
} else {
return message.getBody().trim();
}
}
- private PendingIntent createContentIntent(String conversationUuid) {
- TaskStackBuilder stackBuilder = TaskStackBuilder
- .create(mXmppConnectionService);
+ private PendingIntent createContentIntent(final String conversationUuid) {
+ final TaskStackBuilder stackBuilder = TaskStackBuilder
+ .create(mXmppConnectionService);
stackBuilder.addParentStack(ConversationActivity.class);
- Intent viewConversationIntent = new Intent(mXmppConnectionService,
+ final Intent viewConversationIntent = new Intent(mXmppConnectionService,
ConversationActivity.class);
viewConversationIntent.setAction(Intent.ACTION_VIEW);
- if (conversationUuid!=null) {
+ if (conversationUuid != null) {
viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
conversationUuid);
viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
@@ -311,36 +327,34 @@ public class NotificationService {
stackBuilder.addNextIntent(viewConversationIntent);
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
- PendingIntent.FLAG_UPDATE_CURRENT);
- return resultPendingIntent;
+ return stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent createDeleteIntent() {
- Intent intent = new Intent(mXmppConnectionService,
+ final Intent intent = new Intent(mXmppConnectionService,
XmppConnectionService.class);
intent.setAction(XmppConnectionService.ACTION_CLEAR_NOTIFICATION);
return PendingIntent.getService(mXmppConnectionService, 0, intent, 0);
}
private PendingIntent createDisableForeground() {
- Intent intent = new Intent(mXmppConnectionService,
+ final Intent intent = new Intent(mXmppConnectionService,
XmppConnectionService.class);
intent.setAction(XmppConnectionService.ACTION_DISABLE_FOREGROUND);
return PendingIntent.getService(mXmppConnectionService, 0, intent, 0);
}
- private boolean wasHighlightedOrPrivate(Message message) {
- String nick = message.getConversation().getMucOptions().getActualNick();
- Pattern highlight = generateNickHighlightPattern(nick);
+ private boolean wasHighlightedOrPrivate(final Message message) {
+ final String nick = message.getConversation().getMucOptions().getActualNick();
+ final Pattern highlight = generateNickHighlightPattern(nick);
if (message.getBody() == null || nick == null) {
return false;
}
- Matcher m = highlight.matcher(message.getBody());
+ final Matcher m = highlight.matcher(message.getBody());
return (m.find() || message.getType() == Message.TYPE_PRIVATE);
}
- private static Pattern generateNickHighlightPattern(String nick) {
+ private static Pattern generateNickHighlightPattern(final String nick) {
// We expect a word boundary, i.e. space or start of string, followed by
// the
// nick (matched in case-insensitive manner), followed by optional
@@ -350,17 +364,20 @@ public class NotificationService {
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
}
- public void setOpenConversation(Conversation conversation) {
+ public void setOpenConversation(final Conversation conversation) {
this.mOpenConversation = conversation;
}
- public void setIsInForeground(boolean foreground) {
+ public void setIsInForeground(final boolean foreground) {
+ if (foreground != this.mIsInForeground) {
+ Log.d(Config.LOGTAG,"setIsInForeground("+Boolean.toString(foreground)+")");
+ }
this.mIsInForeground = foreground;
}
- private int getPixel(int dp) {
- DisplayMetrics metrics = mXmppConnectionService.getResources()
- .getDisplayMetrics();
+ private int getPixel(final int dp) {
+ final DisplayMetrics metrics = mXmppConnectionService.getResources()
+ .getDisplayMetrics();
return ((int) (dp * metrics.density));
}
@@ -368,14 +385,14 @@ public class NotificationService {
this.mLastNotification = SystemClock.elapsedRealtime();
}
- private boolean inMiniGracePeriod(Account account) {
- int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD
- : Config.MINI_GRACE_PERIOD * 2;
+ private boolean inMiniGracePeriod(final Account account) {
+ final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD
+ : Config.MINI_GRACE_PERIOD * 2;
return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace);
}
public Notification createForegroundNotification() {
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
+ final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
mBuilder.setSmallIcon(R.drawable.ic_stat_communication_import_export);
mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.conversations_foreground_service));
mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_disable));
@@ -386,14 +403,14 @@ public class NotificationService {
}
public void updateErrorNotification() {
- NotificationManager mNotificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE);
- List<Account> errors = new ArrayList<>();
- for (Account account : mXmppConnectionService.getAccounts()) {
+ final NotificationManager mNotificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE);
+ final List<Account> errors = new ArrayList<>();
+ for (final Account account : mXmppConnectionService.getAccounts()) {
if (account.hasErrorStatus()) {
errors.add(account);
}
}
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
+ final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
if (errors.size() == 0) {
mNotificationManager.cancel(ERROR_NOTIFICATION_ID);
return;
@@ -410,13 +427,12 @@ public class NotificationService {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mXmppConnectionService);
stackBuilder.addParentStack(ConversationActivity.class);
- Intent manageAccountsIntent = new Intent(mXmppConnectionService,ManageAccountActivity.class);
+ final Intent manageAccountsIntent = new Intent(mXmppConnectionService,ManageAccountActivity.class);
stackBuilder.addNextIntent(manageAccountsIntent);
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
+ final PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
- Notification notification = mBuilder.build();
- mNotificationManager.notify(ERROR_NOTIFICATION_ID, notification);
+ mNotificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build());
}
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 41a40224..6bdc55a1 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -32,20 +32,16 @@ import net.java.otr4j.session.SessionStatus;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
-import java.util.TimeZone;
+import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import de.duenndns.ssl.MemorizingTrustManager;
@@ -53,11 +49,11 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable;
-import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.DownloadablePlaceholder;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
@@ -78,12 +74,17 @@ import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PRNGFixes;
import eu.siacs.conversations.utils.PhoneHelper;
+import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
+import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
+import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
+import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
+import eu.siacs.conversations.xmpp.PacketReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.forms.Field;
@@ -97,11 +98,12 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
-public class XmppConnectionService extends Service {
+public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener {
+
+ public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
+ private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+ public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
- public static String ACTION_CLEAR_NOTIFICATION = "clear_notification";
- private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
- public static String ACTION_DISABLE_FOREGROUND = "disable_foreground";
private ContentObserver contactObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -126,7 +128,7 @@ public class XmppConnectionService extends Service {
conversation.resetOtrSession();
}
if (online && (contact.getPresences().size() == 1)) {
- sendUnsendMessages(conversation);
+ sendUnsentMessages(conversation);
}
}
}
@@ -135,18 +137,19 @@ public class XmppConnectionService extends Service {
private MemorizingTrustManager mMemorizingTrustManager;
private NotificationService mNotificationService = new NotificationService(
this);
- private MessageParser mMessageParser = new MessageParser(this);
- private PresenceParser mPresenceParser = new PresenceParser(this);
+ private OnMessagePacketReceived mMessageParser = new MessageParser(this);
+ private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator(this);
private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this);
private List<Account> accounts;
- private final CopyOnWriteArrayList<Conversation> conversations = new CopyOnWriteArrayList<Conversation>();
+ private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this);
private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
this);
private AvatarService mAvatarService = new AvatarService(this);
+ private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
private OnConversationUpdate mOnConversationUpdate = null;
private Integer convChangedListenerCount = 0;
private OnAccountUpdate mOnAccountUpdate = null;
@@ -165,12 +168,13 @@ public class XmppConnectionService extends Service {
for (Conversation conversation : account.pendingConferenceJoins) {
joinMuc(conversation);
}
+ mMessageArchiveService.executePendingQueries(account);
mJingleConnectionManager.cancelInTransmission();
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if (conversation.getAccount() == account) {
conversation.startOtrIfNeeded();
- sendUnsendMessages(conversation);
+ sendUnsentMessages(conversation);
}
}
if (connection != null && connection.getFeatures().csi()) {
@@ -209,13 +213,16 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification();
}
};
+
private int accountChangedListenerCount = 0;
private OnRosterUpdate mOnRosterUpdate = null;
+ private OnUpdateBlocklist mOnUpdateBlocklist = null;
+ private int updateBlocklistListenerCount = 0;
private int rosterChangedListenerCount = 0;
private OnMucRosterUpdate mOnMucRosterUpdate = null;
private int mucRosterChangedListenerCount = 0;
private SecureRandom mRandom;
- private FileObserver fileObserver = new FileObserver(
+ private final FileObserver fileObserver = new FileObserver(
FileBackend.getConversationsImageDirectory()) {
@Override
@@ -225,7 +232,7 @@ public class XmppConnectionService extends Service {
}
}
};
- private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
+ private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@Override
public void onJinglePacketReceived(Account account, JinglePacket packet) {
@@ -239,43 +246,41 @@ public class XmppConnectionService extends Service {
private PendingIntent pendingPingIntent = null;
private WakeLock wakeLock;
private PowerManager pm;
- private OnBindListener mOnBindListener = new OnBindListener() {
+ private final OnBindListener mOnBindListener = new OnBindListener() {
@Override
public void onBind(final Account account) {
account.getRoster().clearPresences();
- account.clearPresences(); // self presences
account.pendingConferenceJoins.clear();
account.pendingConferenceLeaves.clear();
fetchRosterFromServer(account);
fetchBookmarks(account);
- sendPresencePacket(account,
- mPresenceGenerator.sendPresence(account));
+ sendPresencePacket(account,mPresenceGenerator.sendPresence(account));
connectMultiModeConversations(account);
updateConversationUi();
}
};
- private OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
+ private final OnMessageAcknowledged mOnMessageAcknowledgedListener = new OnMessageAcknowledged() {
@Override
public void onMessageAcknowledged(Account account, String uuid) {
- for (Conversation conversation : getConversations()) {
+ for (final Conversation conversation : getConversations()) {
if (conversation.getAccount() == account) {
- for (Message message : conversation.getMessages()) {
- if ((message.getStatus() == Message.STATUS_UNSEND || message
- .getStatus() == Message.STATUS_WAITING)
- && message.getUuid().equals(uuid)) {
- markMessage(message, Message.STATUS_SEND);
- return;
- }
+ Message message = conversation.findUnsentMessageWithUuid(uuid);
+ if (message != null) {
+ markMessage(message, Message.STATUS_SEND);
+ if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) {
+ databaseBackend.updateConversation(conversation);
+ }
}
}
}
}
};
private LruCache<String, Bitmap> mBitmapCache;
- private IqGenerator mIqGenerator = new IqGenerator(this);
+ private final IqGenerator mIqGenerator = new IqGenerator(this);
+ private Thread mPhoneContactMergerThread;
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -299,7 +304,9 @@ public class XmppConnectionService extends Service {
return this.mAvatarService;
}
- public void attachFileToConversation(Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
+ public void attachFileToConversation(final Conversation conversation,
+ final Uri uri,
+ final UiCallback<Message> callback) {
final Message message;
if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "",
@@ -359,13 +366,13 @@ public class XmppConnectionService extends Service {
@Override
public void run() {
try {
- DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri);
+ getFileBackend().copyImageToPrivateStorage(message, uri);
if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
getPgpEngine().encrypt(message, callback);
} else {
callback.success(message);
}
- } catch (FileBackend.FileCopyException e) {
+ } catch (final FileBackend.FileCopyException e) {
callback.error(e.getResId(), message);
}
}
@@ -384,7 +391,7 @@ public class XmppConnectionService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null) {
if (intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS)) {
- mergePhoneContactsWithRoster();
+ PhoneHelper.loadPhoneContacts(getApplicationContext(), new ArrayList<Bundle>(), this);
return START_STICKY;
} else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
logoutAndSave();
@@ -479,11 +486,11 @@ public class XmppConnectionService extends Service {
this.mMemorizingTrustManager = new MemorizingTrustManager(
getApplicationContext());
- int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
- int cacheSize = maxMemory / 8;
+ final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
+ final int cacheSize = maxMemory / 8;
this.mBitmapCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
- protected int sizeOf(String key, Bitmap bitmap) {
+ protected int sizeOf(final String key, final Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
@@ -491,12 +498,12 @@ public class XmppConnectionService extends Service {
this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
this.accounts = databaseBackend.getAccounts();
- for (Account account : this.accounts) {
+ for (final Account account : this.accounts) {
account.initOtrEngine(this);
this.databaseBackend.readRoster(account.getRoster());
}
initConversations();
- this.mergePhoneContactsWithRoster();
+ PhoneHelper.loadPhoneContacts(getApplicationContext(),new ArrayList<Bundle>(), this);
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
this.fileObserver.startWatching();
@@ -517,7 +524,7 @@ public class XmppConnectionService extends Service {
}
@Override
- public void onTaskRemoved(Intent rootIntent) {
+ public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (!getPreferences().getBoolean("keep_foreground_service",false)) {
this.logoutAndSave();
@@ -525,7 +532,7 @@ public class XmppConnectionService extends Service {
}
private void logoutAndSave() {
- for (Account account : accounts) {
+ for (final Account account : accounts) {
databaseBackend.writeRoster(account.getRoster());
if (account.getXmppConnection() != null) {
disconnect(account, false);
@@ -578,26 +585,26 @@ public class XmppConnectionService extends Service {
}
- public XmppConnection createConnection(Account account) {
- SharedPreferences sharedPref = getPreferences();
+ public XmppConnection createConnection(final Account account) {
+ final SharedPreferences sharedPref = getPreferences();
account.setResource(sharedPref.getString("resource", "mobile")
.toLowerCase(Locale.getDefault()));
- XmppConnection connection = new XmppConnection(account, this);
+ final XmppConnection connection = new XmppConnection(account, this);
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection.setOnBindListener(this.mOnBindListener);
- connection
- .setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
+ connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener);
+ connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService);
return connection;
}
- public void sendMessage(Message message) {
- Account account = message.getConversation().getAccount();
+ public void sendMessage(final Message message) {
+ final Account account = message.getConversation().getAccount();
account.deactivateGracePeriod();
- Conversation conv = message.getConversation();
+ final Conversation conv = message.getConversation();
MessagePacket packet = null;
boolean saveInDb = true;
boolean send = false;
@@ -641,12 +648,22 @@ public class XmppConnectionService extends Service {
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
message.getConversation().endOtrIfNeeded();
- failWaitingOtrMessages(message.getConversation());
+ message.getConversation().findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() {
+ @Override
+ public void onMessageFound(Message message) {
+ markMessage(message,Message.STATUS_SEND_FAILED);
+ }
+ });
packet = mMessageGenerator.generatePgpChat(message);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
- failWaitingOtrMessages(message.getConversation());
+ message.getConversation().findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() {
+ @Override
+ public void onMessageFound(Message message) {
+ markMessage(message,Message.STATUS_SEND_FAILED);
+ }
+ });
packet = mMessageGenerator.generateChat(message);
send = true;
}
@@ -689,16 +706,17 @@ public class XmppConnectionService extends Service {
updateConversationUi();
}
- private void sendUnsendMessages(Conversation conversation) {
- for (int i = 0; i < conversation.getMessages().size(); ++i) {
- int status = conversation.getMessages().get(i).getStatus();
- if (status == Message.STATUS_WAITING) {
- resendMessage(conversation.getMessages().get(i));
+ private void sendUnsentMessages(final Conversation conversation) {
+ conversation.findWaitingMessages(new Conversation.OnMessageFound() {
+
+ @Override
+ public void onMessageFound(Message message) {
+ resendMessage(message);
}
- }
+ });
}
- private void resendMessage(Message message) {
+ private void resendMessage(final Message message) {
Account account = message.getConversation().getAccount();
MessagePacket packet = null;
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
@@ -725,7 +743,7 @@ public class XmppConnectionService extends Service {
} else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
mJingleConnectionManager.createNewConnection(message);
}
- } catch (InvalidJidException e) {
+ } catch (final InvalidJidException ignored) {
}
}
@@ -768,47 +786,35 @@ public class XmppConnectionService extends Service {
}
}
- public void fetchRosterFromServer(Account account) {
- IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+ public void fetchRosterFromServer(final Account account) {
+ final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
if (!"".equals(account.getRosterVersion())) {
Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": fetching roster version " + account.getRosterVersion());
} else {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster");
}
- iqPacket.query("jabber:iq:roster").setAttribute("ver",
+ iqPacket.query(Xmlns.ROSTER).setAttribute("ver",
account.getRosterVersion());
- account.getXmppConnection().sendIqPacket(iqPacket,
- new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(final Account account,
- IqPacket packet) {
- Element query = packet.findChild("query");
- if (query != null) {
- account.getRoster().markAllAsNotInRoster();
- mIqParser.rosterItems(account, query);
- }
- }
- });
+ account.getXmppConnection().sendIqPacket(iqPacket, mIqParser);
}
- public void fetchBookmarks(Account account) {
- IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
- Element query = iqPacket.query("jabber:iq:private");
+ public void fetchBookmarks(final Account account) {
+ final IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+ final Element query = iqPacket.query("jabber:iq:private");
query.addChild("storage", "storage:bookmarks");
- OnIqPacketReceived callback = new OnIqPacketReceived() {
+ final PacketReceived callback = new OnIqPacketReceived() {
@Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- Element query = packet.query();
- List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
- Element storage = query.findChild("storage",
+ public void onIqPacketReceived(final Account account, final IqPacket packet) {
+ final Element query = packet.query();
+ final List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
+ final Element storage = query.findChild("storage",
"storage:bookmarks");
if (storage != null) {
- for (Element item : storage.getChildren()) {
+ for (final Element item : storage.getChildren()) {
if (item.getName().equals("conference")) {
- Bookmark bookmark = Bookmark.parse(item, account);
+ final Bookmark bookmark = Bookmark.parse(item, account);
bookmarks.add(bookmark);
Conversation conversation = find(bookmark);
if (conversation != null) {
@@ -826,7 +832,6 @@ public class XmppConnectionService extends Service {
}
};
sendIqPacket(account, iqPacket, callback);
-
}
public void pushBookmarks(Account account) {
@@ -839,53 +844,56 @@ public class XmppConnectionService extends Service {
sendIqPacket(account, iqPacket, null);
}
- private void mergePhoneContactsWithRoster() {
- PhoneHelper.loadPhoneContacts(getApplicationContext(),
- new OnPhoneContactsLoadedListener() {
- @Override
- public void onPhoneContactsLoaded(List<Bundle> phoneContacts) {
- for (Account account : accounts) {
- account.getRoster().clearSystemAccounts();
+ public void onPhoneContactsLoaded(final List<Bundle> phoneContacts) {
+ if (mPhoneContactMergerThread != null) {
+ mPhoneContactMergerThread.interrupt();
+ }
+ mPhoneContactMergerThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ Log.d(Config.LOGTAG,"start merging phone contacts with roster");
+ for (Account account : accounts) {
+ account.getRoster().clearSystemAccounts();
+ for (Bundle phoneContact : phoneContacts) {
+ if (Thread.interrupted()) {
+ Log.d(Config.LOGTAG,"interrupted merging phone contacts");
+ return;
}
- for (Bundle phoneContact : phoneContacts) {
- for (Account account : accounts) {
- Jid jid;
- try {
- jid = Jid.fromString(phoneContact.getString("jid"));
- } catch (final InvalidJidException e) {
- // TODO: Warn if contact import fails here?
- break;
- }
- final Contact contact = account.getRoster()
- .getContact(jid);
- String systemAccount = phoneContact
- .getInt("phoneid")
- + "#"
- + phoneContact.getString("lookup");
- contact.setSystemAccount(systemAccount);
- contact.setPhotoUri(phoneContact
- .getString("photouri"));
- contact.setSystemName(phoneContact
- .getString("displayname"));
- getAvatarService().clear(contact);
- }
+ Jid jid;
+ try {
+ jid = Jid.fromString(phoneContact.getString("jid"));
+ } catch (final InvalidJidException e) {
+ continue;
}
+ final Contact contact = account.getRoster().getContact(jid);
+ String systemAccount = phoneContact.getInt("phoneid")
+ + "#"
+ + phoneContact.getString("lookup");
+ contact.setSystemAccount(systemAccount);
+ contact.setPhotoUri(phoneContact.getString("photouri"));
+ getAvatarService().clear(contact);
+ contact.setSystemName(phoneContact.getString("displayname"));
}
- });
+ }
+ Log.d(Config.LOGTAG,"finished merging phone contacts");
+ updateAccountUi();
+ }
+ });
+ mPhoneContactMergerThread.start();
}
private void initConversations() {
synchronized (this.conversations) {
- Hashtable<String, Account> accountLookupTable = new Hashtable<>();
+ final Map<String, Account> accountLookupTable = new Hashtable<>();
for (Account account : this.accounts) {
accountLookupTable.put(account.getUuid(), account);
}
this.conversations.addAll(databaseBackend.getConversations(Conversation.STATUS_AVAILABLE));
- for (Conversation conv : this.conversations) {
- Account account = accountLookupTable.get(conv.getAccountUuid());
- conv.setAccount(account);
- conv.addAll(0, databaseBackend.getMessages(conv, 50));
- checkDeletedFiles(conv);
+ for (Conversation conversation : this.conversations) {
+ Account account = accountLookupTable.get(conversation.getAccountUuid());
+ conversation.setAccount(account);
+ conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
+ checkDeletedFiles(conversation);
}
}
}
@@ -895,28 +903,26 @@ public class XmppConnectionService extends Service {
}
private void checkDeletedFiles(Conversation conversation) {
- for (Message message : conversation.getMessages()) {
- if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE)
- && message.getEncryption() != Message.ENCRYPTION_PGP) {
+ conversation.findMessagesWithFiles(new Conversation.OnMessageFound() {
+
+ @Override
+ public void onMessageFound(Message message) {
if (!getFileBackend().isFileAvailable(message)) {
message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED));
}
- }
- }
+ }
+ });
}
private void markFileDeleted(String uuid) {
for (Conversation conversation : getConversations()) {
- for (Message message : conversation.getMessages()) {
- if (message.getType() == Message.TYPE_IMAGE
- && message.getEncryption() != Message.ENCRYPTION_PGP
- && message.getUuid().equals(uuid)) {
- if (!getFileBackend().isFileAvailable(message)) {
- message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED));
- updateConversationUi();
- }
- return;
- }
+ Message message = conversation.findMessageWithFileAndUuid(uuid);
+ if (message != null) {
+ if (!getFileBackend().isFileAvailable(message)) {
+ message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED));
+ updateConversationUi();
+ }
+ return;
}
}
}
@@ -952,22 +958,43 @@ public class XmppConnectionService extends Service {
});
}
- public int loadMoreMessages(Conversation conversation, long timestamp) {
- List<Message> messages = databaseBackend.getMessages(conversation, 50,
- timestamp);
- for (Message message : messages) {
- message.setConversation(conversation);
+ public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
+ Log.d(Config.LOGTAG,"load more messages for "+conversation.getName() + " prior to "+MessageGenerator.getTimestamp(timestamp));
+ if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) {
+ return;
}
- conversation.addAll(0, messages);
- return messages.size();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ final Account account = conversation.getAccount();
+ List<Message> messages = databaseBackend.getMessages(conversation, 50,timestamp);
+ if (messages.size() > 0) {
+ conversation.addAll(0, messages);
+ callback.onMoreMessagesLoaded(messages.size(), conversation);
+ } else if (conversation.hasMessagesLeftOnServer()
+ && account.isOnlineAndConnected()
+ && account.getXmppConnection().getFeatures().mam()) {
+ MessageArchiveService.Query query = getMessageArchiveService().query(conversation,0,timestamp - 1);
+ if (query != null) {
+ query.setCallback(callback);
+ }
+ callback.informUser(R.string.fetching_history_from_server);
+ }
+ }
+ }).start();
+ }
+
+ public interface OnMoreMessagesLoaded {
+ public void onMoreMessagesLoaded(int count,Conversation conversation);
+ public void informUser(int r);
}
public List<Account> getAccounts() {
return this.accounts;
}
- public Conversation find(List<Conversation> haystack, Contact contact) {
- for (Conversation conversation : haystack) {
+ public Conversation find(final Iterable<Conversation> haystack, final Contact contact) {
+ for (final Conversation conversation : haystack) {
if (conversation.getContact() == contact) {
return conversation;
}
@@ -975,23 +1002,24 @@ public class XmppConnectionService extends Service {
return null;
}
- public Conversation find(final List<Conversation> haystack,
- final Account account,
- final Jid jid) {
+ public Conversation find(final Iterable<Conversation> haystack, final Account account, final Jid jid) {
if (jid == null ) {
return null;
}
- for (Conversation conversation : haystack) {
+ for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
- && (conversation.getContactJid().toBareJid().equals(jid.toBareJid()))) {
+ && (conversation.getJid().toBareJid().equals(jid.toBareJid()))) {
return conversation;
}
}
return null;
}
- public Conversation findOrCreateConversation(final Account account, final Jid jid,
- final boolean muc) {
+ public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc) {
+ return this.findOrCreateConversation(account,jid,muc,null);
+ }
+
+ public Conversation findOrCreateConversation(final Account account, final Jid jid,final boolean muc, final MessageArchiveService.Query query) {
synchronized (this.conversations) {
Conversation conversation = find(account, jid);
if (conversation != null) {
@@ -1006,7 +1034,7 @@ public class XmppConnectionService extends Service {
} else {
conversation.setMode(Conversation.MODE_SINGLE);
}
- conversation.addAll(0, databaseBackend.getMessages(conversation, 50));
+ conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
this.databaseBackend.updateConversation(conversation);
} else {
String conversationName;
@@ -1025,6 +1053,13 @@ public class XmppConnectionService extends Service {
}
this.databaseBackend.createConversation(conversation);
}
+ if (query == null) {
+ this.mMessageArchiveService.query(conversation);
+ } else {
+ if (query.getConversation() == null) {
+ this.mMessageArchiveService.query(conversation,query.getStart());
+ }
+ }
this.conversations.add(conversation);
updateConversationUi();
return conversation;
@@ -1051,13 +1086,7 @@ public class XmppConnectionService extends Service {
}
}
- public void clearConversationHistory(Conversation conversation) {
- this.databaseBackend.deleteMessagesInConversation(conversation);
- conversation.getMessages().clear();
- updateConversationUi();
- }
-
- public void createAccount(Account account) {
+ public void createAccount(final Account account) {
account.initOtrEngine(this);
databaseBackend.createAccount(account);
this.accounts.add(account);
@@ -1065,7 +1094,7 @@ public class XmppConnectionService extends Service {
updateAccountUi();
}
- public void updateAccount(Account account) {
+ public void updateAccount(final Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
reconnectAccount(account, false);
@@ -1073,9 +1102,30 @@ public class XmppConnectionService extends Service {
getNotificationService().updateErrorNotification();
}
- public void deleteAccount(Account account) {
+ public void updateAccountPasswordOnServer(final Account account, final String newPassword, final OnAccountPasswordChanged callback) {
+ final IqPacket iq = getIqGenerator().generateSetPassword(account, newPassword);
+ sendIqPacket(account, iq, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(final Account account, final IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE_RESULT) {
+ account.setPassword(newPassword);
+ databaseBackend.updateAccount(account);
+ callback.onPasswordChangeSucceeded();
+ } else {
+ callback.onPasswordChangeFailed();
+ }
+ }
+ });
+ }
+
+ public interface OnAccountPasswordChanged {
+ public void onPasswordChangeSucceeded();
+ public void onPasswordChangeFailed();
+ }
+
+ public void deleteAccount(final Account account) {
synchronized (this.conversations) {
- for (Conversation conversation : conversations) {
+ for (final Conversation conversation : conversations) {
if (conversation.getAccount() == account) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
leaveMuc(conversation);
@@ -1147,7 +1197,7 @@ public class XmppConnectionService extends Service {
}
}
- public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ public void setOnRosterUpdateListener(final OnRosterUpdate listener) {
synchronized (this) {
if (checkListeners()) {
switchToForeground();
@@ -1172,6 +1222,31 @@ public class XmppConnectionService extends Service {
}
}
+ public void setOnUpdateBlocklistListener(final OnUpdateBlocklist listener) {
+ synchronized (this) {
+ if (checkListeners()) {
+ switchToForeground();
+ }
+ this.mOnUpdateBlocklist = listener;
+ if (this.updateBlocklistListenerCount < 2) {
+ this.updateBlocklistListenerCount++;
+ }
+ }
+ }
+
+ public void removeOnUpdateBlocklistListener() {
+ synchronized (this) {
+ this.updateBlocklistListenerCount--;
+ if (this.updateBlocklistListenerCount <= 0) {
+ this.updateBlocklistListenerCount = 0;
+ this.mOnUpdateBlocklist = null;
+ if (checkListeners()) {
+ switchToBackground();
+ }
+ }
+ }
+ }
+
public void setOnMucRosterUpdateListener(OnMucRosterUpdate listener) {
synchronized (this) {
if (checkListeners()) {
@@ -1199,7 +1274,9 @@ public class XmppConnectionService extends Service {
private boolean checkListeners() {
return (this.mOnAccountUpdate == null
- && this.mOnConversationUpdate == null && this.mOnRosterUpdate == null);
+ && this.mOnConversationUpdate == null
+ && this.mOnRosterUpdate == null
+ && this.mOnUpdateBlocklist == null);
}
private void switchToForeground() {
@@ -1227,11 +1304,12 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, "app switched into background");
}
- public void connectMultiModeConversations(Account account) {
+ private void connectMultiModeConversations(Account account) {
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
if ((conversation.getMode() == Conversation.MODE_MULTI)
&& (conversation.getAccount() == account)) {
+ conversation.resetMucOptions();
joinMuc(conversation);
}
}
@@ -1251,29 +1329,18 @@ public class XmppConnectionService extends Service {
PresencePacket packet = new PresencePacket();
packet.setFrom(conversation.getAccount().getJid());
packet.setTo(joinJid);
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+ Element x = packet.addChild("x","http://jabber.org/protocol/muc");
if (conversation.getMucOptions().getPassword() != null) {
- Element password = x.addChild("password");
- password.setContent(conversation.getMucOptions().getPassword());
+ x.addChild("password").setContent(conversation.getMucOptions().getPassword());
}
+ x.addChild("history").setAttribute("since",PresenceGenerator.getTimestamp(conversation.getLastMessageTransmitted()));
String sig = account.getPgpSignature();
if (sig != null) {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
- if (conversation.getMessages().size() != 0) {
- final SimpleDateFormat mDateFormat = new SimpleDateFormat(
- "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
- mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- Date date = new Date(conversation.getLatestMessage()
- .getTimeSent() + 1000);
- x.addChild("history").setAttribute("since",
- mDateFormat.format(date));
- }
- packet.addChild(x);
sendPresencePacket(account, packet);
- if (!joinJid.equals(conversation.getContactJid())) {
+ if (!joinJid.equals(conversation.getJid())) {
conversation.setContactJid(joinJid);
databaseBackend.updateConversation(conversation);
}
@@ -1315,7 +1382,7 @@ public class XmppConnectionService extends Service {
@Override
public void onFailure() {
- callback.error(R.string.nick_in_use,conversation);
+ callback.error(R.string.nick_in_use, conversation);
}
});
@@ -1349,14 +1416,14 @@ public class XmppConnectionService extends Service {
account.pendingConferenceLeaves.remove(conversation);
if (account.getStatus() == Account.State.ONLINE) {
PresencePacket packet = new PresencePacket();
- packet.setTo(conversation.getContactJid());
+ packet.setTo(conversation.getJid());
packet.setFrom(conversation.getAccount().getJid());
packet.setAttribute("type", "unavailable");
sendPresencePacket(conversation.getAccount(), packet);
conversation.getMucOptions().setOffline();
conversation.deregisterWithBookmark();
Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()
- + ": leaving muc " + conversation.getContactJid());
+ + ": leaving muc " + conversation.getJid());
} else {
account.pendingConferenceLeaves.add(conversation);
}
@@ -1381,8 +1448,8 @@ public class XmppConnectionService extends Service {
return null;
}
- public void createAdhocConference(final Account account, final List<Jid> jids, final UiCallback<Conversation> callback) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString());
+ public void createAdhocConference(final Account account, final Iterable<Jid> jids, final UiCallback<Conversation> callback) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": creating adhoc conference with " + jids.toString());
if (account.getStatus() == Account.State.ONLINE) {
try {
String server = findConferenceServer(account);
@@ -1434,7 +1501,7 @@ public class XmppConnectionService extends Service {
public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) {
IqPacket request = new IqPacket(IqPacket.TYPE_GET);
- request.setTo(conversation.getContactJid().toBareJid());
+ request.setTo(conversation.getJid().toBareJid());
request.query("http://jabber.org/protocol/muc#owner");
sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() {
@Override
@@ -1448,7 +1515,7 @@ public class XmppConnectionService extends Service {
}
data.submit();
IqPacket set = new IqPacket(IqPacket.TYPE_SET);
- set.setTo(conversation.getContactJid().toBareJid());
+ set.setTo(conversation.getJid().toBareJid());
set.query("http://jabber.org/protocol/muc#owner").addChild(data);
sendIqPacket(account, set, new OnIqPacketReceived() {
@Override
@@ -1486,7 +1553,7 @@ public class XmppConnectionService extends Service {
if (conversation.endOtrIfNeeded()) {
Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": ended otr session with "
- + conversation.getContactJid());
+ + conversation.getJid());
}
}
}
@@ -1528,36 +1595,35 @@ public class XmppConnectionService extends Service {
}
public void onOtrSessionEstablished(Conversation conversation) {
- Account account = conversation.getAccount();
- List<Message> messages = conversation.getMessages();
- Session otrSession = conversation.getOtrSession();
+ final Account account = conversation.getAccount();
+ final Session otrSession = conversation.getOtrSession();
Log.d(Config.LOGTAG,
account.getJid().toBareJid() + " otr session established with "
- + conversation.getContactJid() + "/"
+ + conversation.getJid() + "/"
+ otrSession.getSessionID().getUserID());
- for (Message msg : messages) {
- if ((msg.getStatus() == Message.STATUS_UNSEND || msg.getStatus() == Message.STATUS_WAITING)
- && (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
+ conversation.findUnsentMessagesWithOtrEncryption(new Conversation.OnMessageFound() {
+
+ @Override
+ public void onMessageFound(Message message) {
SessionID id = otrSession.getSessionID();
try {
- msg.setCounterpart(Jid.fromString(id.getAccountID() + "/" + id.getUserID()));
+ message.setCounterpart(Jid.fromString(id.getAccountID() + "/" + id.getUserID()));
} catch (InvalidJidException e) {
- break;
+ return;
}
- if (msg.getType() == Message.TYPE_TEXT) {
- MessagePacket outPacket = mMessageGenerator
- .generateOtrChat(msg, true);
+ if (message.getType() == Message.TYPE_TEXT) {
+ MessagePacket outPacket = mMessageGenerator.generateOtrChat(message, true);
if (outPacket != null) {
- msg.setStatus(Message.STATUS_SEND);
- databaseBackend.updateMessage(msg);
+ message.setStatus(Message.STATUS_SEND);
+ databaseBackend.updateMessage(message);
sendMessagePacket(account, outPacket);
}
- } else if (msg.getType() == Message.TYPE_IMAGE || msg.getType() == Message.TYPE_FILE) {
- mJingleConnectionManager.createNewConnection(msg);
+ } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
+ mJingleConnectionManager.createNewConnection(message);
}
- }
- }
- updateConversationUi();
+ updateConversationUi();
+ }
+ });
}
public boolean renewSymmetricKey(Conversation conversation) {
@@ -1587,17 +1653,17 @@ public class XmppConnectionService extends Service {
return false;
}
- public void pushContactToServer(Contact contact) {
+ public void pushContactToServer(final Contact contact) {
contact.resetOption(Contact.Options.DIRTY_DELETE);
contact.setOption(Contact.Options.DIRTY_PUSH);
- Account account = contact.getAccount();
+ final Account account = contact.getAccount();
if (account.getStatus() == Account.State.ONLINE) {
- boolean ask = contact.getOption(Contact.Options.ASKING);
- boolean sendUpdates = contact
+ final boolean ask = contact.getOption(Contact.Options.ASKING);
+ final boolean sendUpdates = contact
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)
&& contact.getOption(Contact.Options.PREEMPTIVE_GRANT);
- IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
- iq.query("jabber:iq:roster").addChild(contact.asElement());
+ final IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
+ iq.query(Xmlns.ROSTER).addChild(contact.asElement());
account.getXmppConnection().sendIqPacket(iq, null);
if (sendUpdates) {
sendPresencePacket(account,
@@ -1610,7 +1676,8 @@ public class XmppConnectionService extends Service {
}
}
- public void publishAvatar(Account account, Uri image,
+ public void publishAvatar(final Account account,
+ final Uri image,
final UiCallback<Avatar> callback) {
final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
final int size = Config.AVATAR_SIZE;
@@ -1630,13 +1697,13 @@ public class XmppConnectionService extends Service {
callback.error(R.string.error_saving_avatar, avatar);
return;
}
- IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
+ final IqPacket packet = this.mIqGenerator.publishAvatar(avatar);
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
if (result.getType() == IqPacket.TYPE_RESULT) {
- IqPacket packet = XmppConnectionService.this.mIqGenerator
+ final IqPacket packet = XmppConnectionService.this.mIqGenerator
.publishAvatarMetadata(avatar);
sendIqPacket(account, packet, new OnIqPacketReceived() {
@@ -1679,7 +1746,7 @@ public class XmppConnectionService extends Service {
@Override
public void onIqPacketReceived(Account account, IqPacket result) {
final String ERROR = account.getJid().toBareJid()
- + ": fetching avatar for " + avatar.owner + " failed ";
+ + ": fetching avatar for " + avatar.owner + " failed ";
if (result.getType() == IqPacket.TYPE_RESULT) {
avatar.image = mIqParser.avatarData(result);
if (avatar.image != null) {
@@ -1693,7 +1760,7 @@ public class XmppConnectionService extends Service {
updateAccountUi();
} else {
Contact contact = account.getRoster()
- .getContact(avatar.owner);
+ .getContact(avatar.owner);
contact.setAvatar(avatar.getFilename());
getAvatarService().clear(contact);
updateConversationUi();
@@ -1769,7 +1836,7 @@ public class XmppConnectionService extends Service {
Account account = contact.getAccount();
if (account.getStatus() == Account.State.ONLINE) {
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
- Element item = iq.query("jabber:iq:roster").addChild("item");
+ Element item = iq.query(Xmlns.ROSTER).addChild("item");
item.setAttribute("jid", contact.getJid().toString());
item.setAttribute("subscription", "remove");
account.getXmppConnection().sendIqPacket(iq, null);
@@ -1812,12 +1879,13 @@ public class XmppConnectionService extends Service {
public void resetSendingToWaiting(Account account) {
for (Conversation conversation : getConversations()) {
if (conversation.getAccount() == account) {
- for (Message message : conversation.getMessages()) {
- if (message.getType() != Message.TYPE_IMAGE
- && message.getStatus() == Message.STATUS_UNSEND) {
+ conversation.findUnsentTextMessages(new Conversation.OnMessageFound() {
+
+ @Override
+ public void onMessageFound(Message message) {
markMessage(message, Message.STATUS_WAITING);
- }
- }
+ }
+ });
}
}
}
@@ -1828,7 +1896,7 @@ public class XmppConnectionService extends Service {
return false;
} else {
for (Conversation conversation : getConversations()) {
- if (conversation.getContactJid().equals(recipient)
+ if (conversation.getJid().equals(recipient)
&& conversation.getAccount().equals(account)) {
return markMessage(conversation, uuid, status);
}
@@ -1842,15 +1910,13 @@ public class XmppConnectionService extends Service {
if (uuid == null) {
return false;
} else {
- for (Message message : conversation.getMessages()) {
- if (uuid.equals(message.getUuid())
- || (message.getStatus() >= Message.STATUS_SEND && uuid
- .equals(message.getRemoteMsgId()))) {
- markMessage(message, status);
- return true;
- }
+ Message message = conversation.findSentMessageWithUuid(uuid);
+ if (message!=null) {
+ markMessage(message,status);
+ return true;
+ } else {
+ return false;
}
- return false;
}
}
@@ -1904,6 +1970,12 @@ public class XmppConnectionService extends Service {
}
}
+ public void updateBlocklistUi(final OnUpdateBlocklist.Status status) {
+ if (mOnUpdateBlocklist != null) {
+ mOnUpdateBlocklist.OnUpdateBlocklist(status);
+ }
+ }
+
public void updateMucRosterUi() {
if (mOnMucRosterUpdate != null) {
mOnMucRosterUpdate.onMucRosterUpdate();
@@ -1928,29 +2000,22 @@ public class XmppConnectionService extends Service {
return null;
}
- public void markRead(Conversation conversation, boolean calledByUi) {
+ public void markRead(final Conversation conversation) {
mNotificationService.clear(conversation);
- final Message markable = conversation.getLatestMarkableMessage();
conversation.markRead();
- if (confirmMessages() && markable != null && markable.getRemoteMsgId() != null && calledByUi) {
+ }
+
+ public void sendReadMarker(final Conversation conversation) {
+ final Message markable = conversation.getLatestMarkableMessage();
+ this.markRead(conversation);
+ if (confirmMessages() && markable != null && markable.getRemoteMsgId() != null) {
Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()+ ": sending read marker to " + markable.getCounterpart().toString());
Account account = conversation.getAccount();
final Jid to = markable.getCounterpart();
MessagePacket packet = mMessageGenerator.confirm(account, to, markable.getRemoteMsgId());
this.sendMessagePacket(conversation.getAccount(),packet);
}
- if (!calledByUi) {
- updateConversationUi();
- }
- }
-
- public void failWaitingOtrMessages(Conversation conversation) {
- for (Message message : conversation.getMessages()) {
- if (message.getEncryption() == Message.ENCRYPTION_OTR
- && message.getStatus() == Message.STATUS_WAITING) {
- markMessage(message, Message.STATUS_SEND_FAILED);
- }
- }
+ updateConversationUi();
}
public SecureRandom getRNG() {
@@ -1969,14 +2034,6 @@ public class XmppConnectionService extends Service {
return this.mBitmapCache;
}
- public void replyWithNotAcceptable(Account account, MessagePacket packet) {
- if (account.getStatus() == Account.State.ONLINE) {
- MessagePacket error = this.mMessageGenerator
- .generateNotAcceptable(packet);
- sendMessagePacket(account, error);
- }
- }
-
public void syncRosterToDisk(final Account account) {
new Thread(new Runnable() {
@@ -1989,12 +2046,12 @@ public class XmppConnectionService extends Service {
}
public List<String> getKnownHosts() {
- List<String> hosts = new ArrayList<>();
- for (Account account : getAccounts()) {
+ final List<String> hosts = new ArrayList<>();
+ for (final Account account : getAccounts()) {
if (!hosts.contains(account.getServer().toString())) {
hosts.add(account.getServer().toString());
}
- for (Contact contact : account.getRoster().getContacts()) {
+ for (final Contact contact : account.getRoster().getContacts()) {
if (contact.showInRoster()) {
final String server = contact.getServer().toString();
if (server != null && !hosts.contains(server)) {
@@ -2007,10 +2064,10 @@ public class XmppConnectionService extends Service {
}
public List<String> getKnownConferenceHosts() {
- ArrayList<String> mucServers = new ArrayList<>();
- for (Account account : accounts) {
+ final ArrayList<String> mucServers = new ArrayList<>();
+ for (final Account account : accounts) {
if (account.getXmppConnection() != null) {
- String server = account.getXmppConnection().getMucServer();
+ final String server = account.getXmppConnection().getMucServer();
if (server != null && !mucServers.contains(server)) {
mucServers.add(server);
}
@@ -2033,9 +2090,8 @@ public class XmppConnectionService extends Service {
}
}
- public void sendIqPacket(Account account, IqPacket packet,
- OnIqPacketReceived callback) {
- XmppConnection connection = account.getXmppConnection();
+ public void sendIqPacket(final Account account, final IqPacket packet, final PacketReceived callback) {
+ final XmppConnection connection = account.getXmppConnection();
if (connection != null) {
connection.sendIqPacket(packet, callback);
}
@@ -2053,10 +2109,16 @@ public class XmppConnectionService extends Service {
return this.mIqGenerator;
}
+ public IqParser getIqParser() { return this.mIqParser; }
+
public JingleConnectionManager getJingleConnectionManager() {
return this.mJingleConnectionManager;
}
+ public MessageArchiveService getMessageArchiveService() {
+ return this.mMessageArchiveService;
+ }
+
public List<Contact> findContacts(Jid jid) {
ArrayList<Contact> contacts = new ArrayList<>();
for (Account account : getAccounts()) {
@@ -2078,8 +2140,8 @@ public class XmppConnectionService extends Service {
return this.mHttpConnectionManager;
}
- public void resendFailedMessages(Message message) {
- List<Message> messages = new ArrayList<>();
+ public void resendFailedMessages(final Message message) {
+ final Collection<Message> messages = new ArrayList<>();
Message current = message;
while (current.getStatus() == Message.STATUS_SEND_FAILED) {
messages.add(current);
@@ -2089,12 +2151,23 @@ public class XmppConnectionService extends Service {
break;
}
}
- for (Message msg : messages) {
+ for (final Message msg : messages) {
markMessage(msg, Message.STATUS_WAITING);
this.resendMessage(msg);
}
}
+ public void clearConversationHistory(final Conversation conversation) {
+ conversation.clearMessages();
+ conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ databaseBackend.deleteMessagesInConversation(conversation);
+ }
+ }).start();
+ }
+
public interface OnConversationUpdate {
public void onConversationUpdate();
}
@@ -2121,4 +2194,35 @@ public class XmppConnectionService extends Service {
return XmppConnectionService.this;
}
}
+
+ public void sendBlockRequest(final Blockable blockable) {
+ if (blockable != null && blockable.getBlockedJid() != null) {
+ final Jid jid = blockable.getBlockedJid();
+ this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetBlockRequest(jid), new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(final Account account, final IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE_RESULT) {
+ account.getBlocklist().add(jid);
+ updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
+ }
+ }
+ });
+ }
+ }
+
+ public void sendUnblockRequest(final Blockable blockable) {
+ if (blockable != null && blockable.getJid() != null) {
+ final Jid jid = blockable.getBlockedJid();
+ this.sendIqPacket(blockable.getAccount(), getIqGenerator().generateSetUnblockRequest(jid), new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(final Account account, final IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE_RESULT) {
+ account.getBlocklist().remove(jid);
+ updateBlocklistUi(OnUpdateBlocklist.Status.UNBLOCKED);
+ }
+ }
+ });
+ }
+ }
}