aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu')
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java5
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/OtrService.java24
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/PgpEngine.java15
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java4
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Bookmark.java7
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java8
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java11
-rw-r--r--src/main/java/eu/siacs/conversations/entities/ListItem.java2
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java37
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java4
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java8
-rw-r--r--src/main/java/eu/siacs/conversations/generator/IqGenerator.java8
-rw-r--r--src/main/java/eu/siacs/conversations/generator/MessageGenerator.java9
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java199
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java17
-rw-r--r--src/main/java/eu/siacs/conversations/parser/AbstractParser.java35
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java9
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java26
-rw-r--r--src/main/java/eu/siacs/conversations/parser/PresenceParser.java23
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java14
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java387
-rw-r--r--src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java1
-rw-r--r--src/main/java/eu/siacs/conversations/services/AvatarService.java283
-rw-r--r--src/main/java/eu/siacs/conversations/services/MessageArchiveService.java10
-rw-r--r--src/main/java/eu/siacs/conversations/services/NotificationService.java47
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java208
-rw-r--r--src/main/java/eu/siacs/conversations/ui/AboutPreference.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java9
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java1
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java9
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java67
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java152
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java11
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditMessage.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java1
-rw-r--r--src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java15
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java56
-rw-r--r--src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java19
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java54
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java10
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java62
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java38
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java25
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java152
-rw-r--r--src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java93
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java1
-rw-r--r--src/main/java/eu/siacs/conversations/utils/DNSHelper.java11
-rw-r--r--src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java23
-rw-r--r--src/main/java/eu/siacs/conversations/utils/ExifHelper.java12
-rw-r--r--src/main/java/eu/siacs/conversations/utils/PRNGFixes.java5
-rw-r--r--src/main/java/eu/siacs/conversations/utils/PhoneHelper.java8
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java58
-rw-r--r--src/main/java/eu/siacs/conversations/xml/Element.java6
-rw-r--r--src/main/java/eu/siacs/conversations/xml/XmlReader.java7
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java62
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java96
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java8
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java21
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java33
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java2
61 files changed, 1569 insertions, 970 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index 9ee221cc..2ba1177e 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -32,7 +32,7 @@ public final class Config {
public static final int MINI_GRACE_PERIOD = 750;
public static final int AVATAR_SIZE = 192;
- public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
+ public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.PNG;
public static final int IMAGE_SIZE = 1920;
public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG;
@@ -41,9 +41,12 @@ public final class Config {
public static final int MESSAGE_MERGE_WINDOW = 20;
+ public static final boolean UTF8_EMOTICONS = false;
+
public static final int PAGE_SIZE = 50;
public static final int MAX_NUM_PAGES = 3;
+ public static final int PROGRESS_UI_UPDATE_INTERVAL = 750;
public static final int REFRESH_UI_INTERVAL = 500;
public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb
diff --git a/src/main/java/eu/siacs/conversations/crypto/OtrService.java b/src/main/java/eu/siacs/conversations/crypto/OtrService.java
index 1804704e..8a6bfc44 100644
--- a/src/main/java/eu/siacs/conversations/crypto/OtrService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/OtrService.java
@@ -26,11 +26,18 @@ import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -110,7 +117,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
mXmppConnectionService.updateConversationUi();
}
} catch (InvalidJidException e) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": smp in invalid session "+id.toString());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": smp in invalid session "+id.toString());
}
}
@@ -151,7 +158,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
this.saveKey();
mXmppConnectionService.databaseBackend.updateAccount(account);
} catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"error generating key pair " + e.getMessage());
}
}
@@ -185,7 +192,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
Jid jid = Jid.fromSessionID(session);
Conversation conversation = mXmppConnectionService.find(account,jid);
if (conversation != null && conversation.setOutgoingChatState(Config.DEFAULT_CHATSTATE)) {
- if (mXmppConnectionService.sendChatStates()) {
+ if (ConversationsPlusPreferences.chatStates()) {
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
}
}
@@ -217,7 +224,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
@Override
public void showError(SessionID arg0, String arg1) throws OtrException {
- Log.d(Config.LOGTAG,"show error");
+ Logging.d(Config.LOGTAG,"show error");
}
@Override
@@ -252,7 +259,8 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
@Override
public void unreadableMessageReceived(SessionID session) throws OtrException {
- Log.d(Config.LOGTAG,"unreadable message received");
+ Logging.d(Config.LOGTAG,"unreadable message received");
+ // Hier update des contents fuer FS#96
sendOtrErrorMessage(session, "You sent me an unreadable OTR-encrypted message");
}
@@ -266,8 +274,8 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
.generateOtrError(jid, id, errorText);
packet.setFrom(account.getJid());
mXmppConnectionService.sendMessagePacket(account,packet);
- Log.d(Config.LOGTAG,packet.toString());
- Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()
+ Logging.d(Config.LOGTAG,packet.toString());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid().toString()
+": unreadable OTR message in "+conversation.getName());
}
} catch (InvalidJidException e) {
@@ -282,7 +290,7 @@ public class OtrService extends OtrCryptoEngineImpl implements OtrEngineHost {
@Override
public void verify(SessionID id, String fingerprint, boolean approved) {
- Log.d(Config.LOGTAG,"OtrService.verify("+id.toString()+","+fingerprint+","+String.valueOf(approved)+")");
+ Logging.d(Config.LOGTAG,"OtrService.verify("+id.toString()+","+fingerprint+","+String.valueOf(approved)+")");
try {
final Jid jid = Jid.fromSessionID(id);
Conversation conversation = this.mXmppConnectionService.find(this.account,jid);
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
index 624d1b13..1f889cd8 100644
--- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java
@@ -17,6 +17,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -61,7 +64,9 @@ public class PgpEngine {
final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager();
if (message.trusted()
&& message.treatAsDownloadable() != Message.Decision.NEVER
- && manager.getAutoAcceptFileSize() > 0) {
+ && ConversationsPlusPreferences.autoDownloadFileLink()
+ && mXmppConnectionService.isDownloadAllowedInConnection()
+ && ConversationsPlusPreferences.autoAcceptFileSize() > 0) {
manager.createNewDownloadConnection(message);
}
mXmppConnectionService.updateMessage(message);
@@ -102,7 +107,7 @@ public class PgpEngine {
OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS:
URL url = message.getFileParams().url;
- mXmppConnectionService.getFileBackend().updateFileParams(message,url);
+ MessageUtil.updateFileParams(message, url);
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
PgpEngine.this.mXmppConnectionService
.updateMessage(message);
@@ -168,7 +173,7 @@ public class PgpEngine {
String[] lines = os.toString().split("\n");
for (int i = 2; i < lines.length - 1; ++i) {
if (!lines[i].contains("Version")) {
- encryptedMessageBody.append(lines[i].trim());
+ encryptedMessageBody.append(lines[i]);
}
}
message.setEncryptedBody(encryptedMessageBody
@@ -250,7 +255,7 @@ public class PgpEngine {
pgpSig.append("-----BEGIN PGP SIGNATURE-----");
pgpSig.append('\n');
pgpSig.append('\n');
- pgpSig.append(signature.replace("\n", "").trim());
+ pgpSig.append(signature.replace("\n", ""));
pgpSig.append('\n');
pgpSig.append("-----END PGP SIGNATURE-----");
Intent params = new Intent();
@@ -330,7 +335,7 @@ public class PgpEngine {
sig = false;
} else {
if (!line.contains("Version")) {
- signatureBuilder.append(line.trim());
+ signatureBuilder.append(line);
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 4abfc801..0f37ea61 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -162,6 +162,10 @@ public class Account extends AbstractEntity {
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
+ public Account() {
+ this.uuid = "0";
+ }
+
public Account(final Jid jid, final String password) {
this(java.util.UUID.randomUUID().toString(), jid,
password, 0, null, "", null, null, null, 5222);
diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
index acb4bf1a..d0a951b3 100644
--- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.entities;
+import android.graphics.Color;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -74,6 +76,11 @@ public class Bookmark extends Element implements ListItem {
return tags;
}
+ @Override
+ public int getStatusColor() {
+ return Color.parseColor("#259B23");
+ }
+
public String getNick() {
return this.findChildContent("nick");
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index c2d8b278..6d252376 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.entities;
import android.content.ContentValues;
import android.database.Cursor;
+import android.graphics.Color;
import org.json.JSONArray;
import org.json.JSONException;
@@ -155,11 +156,16 @@ public class Contact implements ListItem, Blockable {
return tags;
}
+ @Override
+ public int getStatusColor() {
+ return Color.parseColor(UIHelper.getStatusColor(getMostAvailableStatus()));
+ }
+
public boolean match(String needle) {
if (needle == null || needle.isEmpty()) {
return true;
}
- needle = needle.toLowerCase(Locale.US).trim();
+ needle = needle.toLowerCase(Locale.US);
String[] parts = needle.split("\\s+");
if (parts.length > 1) {
for(int i = 0; i < parts.length; ++i) {
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index 22607fc6..38791d28 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -20,6 +20,7 @@ import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@@ -824,10 +825,16 @@ public class Conversation extends AbstractEntity implements Blockable {
synchronized (this.messages) {
int count = 0;
for(int i = this.messages.size() - 1; i >= 0; --i) {
- if (this.messages.get(i).isRead()) {
+ Message message = this.messages.get(i);
+ if (message.isRead()) {
return count;
}
- ++count;
+ if (getMode() == Conversation.MODE_SINGLE
+ || ConversationsPlusPreferences.alwaysNotifyInConference()
+ || account.getXmppConnectionService().getNotificationService().wasHighlightedOrPrivate(message)
+ ) {
+ ++count;
+ }
}
return count;
}
diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java
index efc1c2b9..aba2aef2 100644
--- a/src/main/java/eu/siacs/conversations/entities/ListItem.java
+++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java
@@ -11,6 +11,8 @@ public interface ListItem extends Comparable<ListItem> {
public List<Tag> getTags();
+ public int getStatusColor();
+
public final class Tag {
private final String name;
private final int color;
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index f3d891e8..8d0571a4 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -347,16 +347,16 @@ public class Message extends AbstractEntity {
public boolean equals(Message message) {
if (this.serverMsgId != null && message.getServerMsgId() != null) {
return this.serverMsgId.equals(message.getServerMsgId());
- } else if (this.body == null || this.counterpart == null) {
+ } else if (this.getBody() == null || this.counterpart == null) {
return false;
} else {
String body, otherBody;
if (this.hasFileOnRemoteHost()) {
body = getFileParams().url.toString();
- otherBody = message.body == null ? null : message.body.trim();
+ otherBody = message.getBody() == null ? null : message.getBody();
} else {
- body = this.body;
- otherBody = message.body;
+ body = this.getBody();
+ otherBody = message.getBody();
}
if (message.getRemoteMsgId() != null) {
return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
@@ -415,13 +415,11 @@ public class Message extends AbstractEntity {
this.getCounterpart().equals(message.getCounterpart()) &&
(message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
!GeoHelper.isGeoUri(message.getBody()) &&
- !GeoHelper.isGeoUri(this.body) &&
+ !GeoHelper.isGeoUri(this.getBody()) &&
message.treatAsDownloadable() == Decision.NEVER &&
this.treatAsDownloadable() == Decision.NEVER &&
!message.getBody().startsWith(ME_COMMAND) &&
- !this.getBody().startsWith(ME_COMMAND) &&
- !this.bodyIsHeart() &&
- !message.bodyIsHeart() &&
+ !this.getBody().startsWith(ME_COMMAND)
this.isTrusted() == message.isTrusted()
);
}
@@ -443,7 +441,7 @@ public class Message extends AbstractEntity {
while(current.mergeable(current.next())) {
current = current.next();
body.append(MERGE_SEPARATOR);
- body.append(current.getBody().trim());
+ body.append(current.getBody());
}
return body.toString();
}
@@ -543,7 +541,7 @@ public class Message extends AbstractEntity {
}
} else {
try {
- return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
+ return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody())));
} catch (MalformedURLException e) {
return null;
}
@@ -551,7 +549,12 @@ public class Message extends AbstractEntity {
}
public Decision treatAsDownloadable() {
- if (body.trim().contains(" ")) {
+ /**
+ * there are a few cases where spaces result in an unwanted behavior, e.g.
+ * "http://example.com/image.jpg" text that will not be shown /abc.png"
+ * or more than one image link in one message.
+ */
+ if (getBody().contains(" ")) {
return Decision.NEVER;
}
try {
@@ -584,10 +587,6 @@ public class Message extends AbstractEntity {
}
}
- public boolean bodyIsHeart() {
- return body != null && UIHelper.HEARTS.contains(body.trim());
- }
-
public FileParams getFileParams() {
FileParams params = getLegacyFileParams();
if (params != null) {
@@ -597,10 +596,10 @@ public class Message extends AbstractEntity {
if (this.transferable != null) {
params.size = this.transferable.getFileSize();
}
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split("\\|");
+ String parts[] = this.getBody().split("\\|");
switch (parts.length) {
case 1:
try {
@@ -659,10 +658,10 @@ public class Message extends AbstractEntity {
public FileParams getLegacyFileParams() {
FileParams params = new FileParams();
- if (body == null) {
+ if (this.getBody() == null) {
return params;
}
- String parts[] = body.split(",");
+ String parts[] = this.getBody().split(",");
if (parts.length == 3) {
try {
params.size = Long.parseLong(parts[0]);
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index 7f4ded11..068dbf83 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -7,13 +7,17 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.forms.Field;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.pep.Avatar;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
@SuppressLint("DefaultLocale")
public class MucOptions {
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index 5741af53..c30ae5d8 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -15,6 +15,8 @@ import java.util.TimeZone;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.PhoneHelper;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.tzur.conversations.Settings;
public abstract class AbstractGenerator {
private final String[] FEATURES = {
@@ -61,7 +63,7 @@ public abstract class AbstractGenerator {
public String getCapHash() {
StringBuilder s = new StringBuilder();
- s.append("client/" + IDENTITY_TYPE + "//" + getIdentityName() + "<");
+ s.append("client/" + IDENTITY_TYPE + "//" + ConversationsPlusApplication.getNameAndVersion() + "<");
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
@@ -73,7 +75,7 @@ public abstract class AbstractGenerator {
s.append(feature + "<");
}
byte[] sha1 = md.digest(s.toString().getBytes());
- return new String(Base64.encode(sha1, Base64.DEFAULT)).trim();
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
}
public static String getTimestamp(long time) {
@@ -84,7 +86,7 @@ public abstract class AbstractGenerator {
public List<String> getFeatures() {
ArrayList<String> features = new ArrayList<>();
features.addAll(Arrays.asList(FEATURES));
- if (mXmppConnectionService.confirmMessages()) {
+ if (Settings.CONFIRM_MESSAGE_RECEIVED) {
features.addAll(Arrays.asList(MESSAGE_CONFIRMATION_FEATURES));
}
Collections.sort(features);
diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
index 345f68ae..6bc1f0fc 100644
--- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java
@@ -15,6 +15,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
@@ -45,7 +47,7 @@ public class IqGenerator extends AbstractGenerator {
final Element identity = query.addChild("identity");
identity.setAttribute("category", "client");
identity.setAttribute("type", IDENTITY_TYPE);
- identity.setAttribute("name", getIdentityName());
+ identity.setAttribute("name", ConversationsPlusApplication.getNameAndVersion());
for (final String feature : getFeatures()) {
query.addChild("feature").setAttribute("var", feature);
}
@@ -55,8 +57,8 @@ public class IqGenerator extends AbstractGenerator {
public IqPacket versionResponse(final IqPacket request) {
final IqPacket packet = request.generateResponse(IqPacket.TYPE.RESULT);
Element query = packet.query("jabber:iq:version");
- query.addChild("name").setContent(IDENTITY_NAME);
- query.addChild("version").setContent(getIdentityVersion());
+ query.addChild("name").setContent(ConversationsPlusApplication.getName());
+ query.addChild("version").setContent(ConversationsPlusApplication.getVersion());
return packet;
}
diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
index b849f56f..9b5dabb0 100644
--- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java
@@ -9,6 +9,11 @@ import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
+import net.java.otr4j.OtrException;
+import net.java.otr4j.session.Session;
+
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
@@ -32,13 +37,13 @@ public class MessageGenerator extends AbstractGenerator {
packet.setTo(message.getCounterpart());
packet.setType(MessagePacket.TYPE_CHAT);
packet.addChild("markable", "urn:xmpp:chat-markers:0");
- if (this.mXmppConnectionService.indicateReceived()) {
+ if (ConversationsPlusPreferences.indicateReceived()) {
packet.addChild("request", "urn:xmpp:receipts");
}
} else if (message.getType() == Message.TYPE_PRIVATE) {
packet.setTo(message.getCounterpart());
packet.setType(MessagePacket.TYPE_CHAT);
- if (this.mXmppConnectionService.indicateReceived()) {
+ if (ConversationsPlusPreferences.indicateReceived()) {
packet.addChild("request", "urn:xmpp:receipts");
}
} else {
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 455a0b14..516d3141 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -2,33 +2,29 @@ package eu.siacs.conversations.http;
import android.content.Intent;
import android.net.Uri;
-import android.os.PowerManager;
-import android.util.Log;
+import android.os.SystemClock;
import java.io.BufferedInputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
import java.net.MalformedURLException;
-import java.net.Proxy;
import java.net.URL;
import java.util.Arrays;
-import java.util.concurrent.CancellationException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
-import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -43,13 +39,11 @@ public class HttpDownloadConnection implements Transferable {
private int mStatus = Transferable.STATUS_UNKNOWN;
private boolean acceptedAutomatically = false;
private int mProgress = 0;
- private boolean mUseTor = false;
- private boolean canceled = false;
+ private long mLastGuiRefresh = 0;
public HttpDownloadConnection(HttpConnectionManager manager) {
this.mHttpConnectionManager = manager;
this.mXmppConnectionService = manager.getXmppConnectionService();
- this.mUseTor = mXmppConnectionService.useTorToConnect();
}
@Override
@@ -74,18 +68,13 @@ public class HttpDownloadConnection implements Transferable {
this.message = message;
this.message.setTransferable(this);
try {
- if (message.hasFileOnRemoteHost()) {
- mUrl = message.getFileParams().url;
- } else {
- mUrl = new URL(message.getBody());
- }
+ mUrl = new URL(message.getBody());
String[] parts = mUrl.getPath().toLowerCase().split("\\.");
String lastPart = parts.length >= 1 ? parts[parts.length - 1] : null;
String secondToLast = parts.length >= 2 ? parts[parts.length -2] : null;
if ("pgp".equals(lastPart) || "gpg".equals(lastPart)) {
this.message.setEncryption(Message.ENCRYPTION_PGP);
- } else if (message.getEncryption() != Message.ENCRYPTION_OTR
- && message.getEncryption() != Message.ENCRYPTION_AXOLOTL) {
+ } else if (message.getEncryption() != Message.ENCRYPTION_OTR) {
this.message.setEncryption(Message.ENCRYPTION_NONE);
}
String extension;
@@ -95,14 +84,13 @@ public class HttpDownloadConnection implements Transferable {
extension = lastPart;
}
message.setRelativeFilePath(message.getUuid()+"."+extension);
- this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
+ this.file = FileBackend.getFile(message, false);
String reference = mUrl.getRef();
if (reference != null && reference.length() == 96) {
- this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
+ this.file.setKey(CryptoHelper.hexToBytes(reference));
}
- if ((this.message.getEncryption() == Message.ENCRYPTION_OTR
- || this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL)
+ if (this.message.getEncryption() == Message.ENCRYPTION_OTR
&& this.file.getKey() == null) {
this.message.setEncryption(Message.ENCRYPTION_NONE);
}
@@ -116,15 +104,9 @@ public class HttpDownloadConnection implements Transferable {
new Thread(new FileSizeChecker(interactive)).start();
}
- @Override
public void cancel() {
- this.canceled = true;
mHttpConnectionManager.finishConnection(this);
- if (message.isFileOrImage()) {
- message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
- } else {
- message.setTransferable(null);
- }
+ message.setTransferable(null);
mXmppConnectionService.updateConversationUi();
}
@@ -134,9 +116,6 @@ public class HttpDownloadConnection implements Transferable {
mXmppConnectionService.sendBroadcast(intent);
message.setTransferable(null);
mHttpConnectionManager.finishConnection(this);
- if (message.getEncryption() == Message.ENCRYPTION_PGP) {
- message.getConversation().getAccount().getPgpDecryptionService().add(message);
- }
mXmppConnectionService.updateConversationUi();
if (acceptedAutomatically) {
mXmppConnectionService.getNotificationService().push(message);
@@ -148,17 +127,6 @@ public class HttpDownloadConnection implements Transferable {
mXmppConnectionService.updateConversationUi();
}
- private void showToastForException(Exception e) {
- e.printStackTrace();
- if (e instanceof java.net.UnknownHostException) {
- mXmppConnectionService.showErrorToastInUi(R.string.download_failed_server_not_found);
- } else if (e instanceof java.net.ConnectException) {
- mXmppConnectionService.showErrorToastInUi(R.string.download_failed_could_not_connect);
- } else if (!(e instanceof CancellationException)) {
- mXmppConnectionService.showErrorToastInUi(R.string.download_failed_file_not_found);
- }
- }
-
private class FileSizeChecker implements Runnable {
private boolean interactive = false;
@@ -178,15 +146,15 @@ public class HttpDownloadConnection implements Transferable {
HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message);
return;
} catch (IOException e) {
- Log.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage());
+ Logging.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage());
if (interactive) {
- showToastForException(e);
+ mXmppConnectionService.showErrorToastInUi(R.string.file_not_found_on_remote_host);
}
cancel();
return;
}
file.setExpectedSize(size);
- if (mHttpConnectionManager.hasStoragePermission() && size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
+ if (size != -1 && size <= ConversationsPlusPreferences.autoAcceptFileSize()) {
HttpDownloadConnection.this.acceptedAutomatically = true;
new Thread(new FileDownloader(interactive)).start();
} else {
@@ -197,33 +165,22 @@ public class HttpDownloadConnection implements Transferable {
}
private long retrieveFileSize() throws IOException {
+ Logging.d(Config.LOGTAG,"retrieve file size. interactive:"+String.valueOf(interactive));
+ changeStatus(STATUS_CHECKING);
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ connection.setRequestMethod("HEAD");
+ if (connection instanceof HttpsURLConnection) {
+ mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
+ }
+ connection.connect();
+ String contentLength = connection.getHeaderField("Content-Length");
+ if (contentLength == null) {
+ return -1;
+ }
try {
- Log.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive));
- changeStatus(STATUS_CHECKING);
- HttpURLConnection connection;
- if (mUseTor) {
- connection = (HttpURLConnection) mUrl.openConnection(mHttpConnectionManager.getProxy());
- } else {
- connection = (HttpURLConnection) mUrl.openConnection();
- }
- connection.setRequestMethod("HEAD");
- Log.d(Config.LOGTAG,"url: "+connection.getURL().toString());
- Log.d(Config.LOGTAG,"connection: "+connection.toString());
- connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName());
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
- }
- connection.connect();
- String contentLength = connection.getHeaderField("Content-Length");
- connection.disconnect();
- if (contentLength == null) {
- throw new IOException();
- }
return Long.parseLong(contentLength, 10);
- } catch (IOException e) {
- throw e;
} catch (NumberFormatException e) {
- throw new IOException();
+ return -1;
}
}
@@ -233,8 +190,6 @@ public class HttpDownloadConnection implements Transferable {
private boolean interactive = false;
- private OutputStream os;
-
public FileDownloader(boolean interactive) {
this.interactive = interactive;
}
@@ -248,79 +203,42 @@ public class HttpDownloadConnection implements Transferable {
finish();
} catch (SSLHandshakeException e) {
changeStatus(STATUS_OFFER);
- } catch (Exception e) {
- if (interactive) {
- showToastForException(e);
- }
+ } catch (IOException e) {
+ mXmppConnectionService.showErrorToastInUi(R.string.file_not_found_on_remote_host);
cancel();
}
}
- private void download() throws Exception {
- InputStream is = null;
- PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid());
- try {
- wakeLock.acquire();
- HttpURLConnection connection;
- if (mUseTor) {
- connection = (HttpURLConnection) mUrl.openConnection(mHttpConnectionManager.getProxy());
- } else {
- connection = (HttpURLConnection) mUrl.openConnection();
- }
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
- }
- connection.setRequestProperty("User-Agent",mXmppConnectionService.getIqGenerator().getIdentityName());
- final boolean tryResume = file.exists() && file.getKey() == null;
- if (tryResume) {
- Log.d(Config.LOGTAG,"http download trying resume");
- long size = file.getSize();
- connection.setRequestProperty("Range", "bytes="+size+"-");
- }
- connection.connect();
- is = new BufferedInputStream(connection.getInputStream());
- boolean serverResumed = "bytes".equals(connection.getHeaderField("Accept-Ranges"));
- long transmitted = 0;
- long expected = file.getExpectedSize();
- if (tryResume && serverResumed) {
- Log.d(Config.LOGTAG,"server resumed");
- transmitted = file.getSize();
- updateProgress((int) ((((double) transmitted) / expected) * 100));
- os = AbstractConnectionManager.createAppendedOutputStream(file);
- } else {
- file.getParentFile().mkdirs();
- file.createNewFile();
- os = AbstractConnectionManager.createOutputStream(file, true);
- }
- int count = -1;
- byte[] buffer = new byte[1024];
- while ((count = is.read(buffer)) != -1) {
- transmitted += count;
- os.write(buffer, 0, count);
- updateProgress((int) ((((double) transmitted) / expected) * 100));
- if (canceled) {
- throw new CancellationException();
- }
- }
- } catch (CancellationException | IOException e) {
- throw e;
- } finally {
- if (os != null) {
- try {
- os.flush();
- } catch (final IOException ignored) {
-
- }
- }
- FileBackend.close(os);
- FileBackend.close(is);
- wakeLock.release();
+ private void download() throws SSLHandshakeException, IOException {
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ if (connection instanceof HttpsURLConnection) {
+ mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
}
+ connection.connect();
+ BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ OutputStream os = file.createOutputStream();
+ if (os == null) {
+ throw new IOException();
+ }
+ long transmitted = 0;
+ long expected = file.getExpectedSize();
+ int count = -1;
+ byte[] buffer = new byte[1024];
+ while ((count = is.read(buffer)) != -1) {
+ transmitted += count;
+ os.write(buffer, 0, count);
+ updateProgress((int) ((((double) transmitted) / expected) * 100));
+ }
+ os.flush();
+ os.close();
+ is.close();
}
private void updateImageBounds() {
message.setType(Message.TYPE_FILE);
- mXmppConnectionService.getFileBackend().updateFileParams(message, mUrl);
+ MessageUtil.updateFileParams(message, mUrl);
mXmppConnectionService.updateMessage(message);
}
@@ -328,7 +246,10 @@ public class HttpDownloadConnection implements Transferable {
public void updateProgress(int i) {
this.mProgress = i;
- mXmppConnectionService.updateConversationUi();
+ if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > Config.PROGRESS_UI_UPDATE_INTERVAL) {
+ this.mLastGuiRefresh = SystemClock.elapsedRealtime();
+ mXmppConnectionService.updateConversationUi();
+ }
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
index 1e4b9102..553988ae 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
@@ -20,6 +20,10 @@ import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+import de.thedevstack.conversationsplus.utils.StreamUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.DownloadableFile;
@@ -162,7 +166,7 @@ public class HttpUploadConnection implements Transferable {
PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_upload_"+message.getUuid());
try {
wakeLock.acquire();
- Log.d(Config.LOGTAG, "uploading to " + mPutUrl.toString());
+ Logging.d(Config.LOGTAG, "uploading to " + mPutUrl.toString());
if (mUseTor) {
connection = (HttpURLConnection) mPutUrl.openConnection(mHttpConnectionManager.getProxy());
} else {
@@ -191,11 +195,11 @@ public class HttpUploadConnection implements Transferable {
mFileInputStream.close();
int code = connection.getResponseCode();
if (code == 200 || code == 201) {
- Log.d(Config.LOGTAG, "finished uploading file");
+ Logging.d(Config.LOGTAG, "finished uploading file");
if (key != null) {
mGetUrl = new URL(mGetUrl.toString() + "#" + CryptoHelper.bytesToHex(key));
}
- mXmppConnectionService.getFileBackend().updateFileParams(message, mGetUrl);
+ MessageUtil.updateFileParams(message, mGetUrl);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
mXmppConnectionService.sendBroadcast(intent);
@@ -225,12 +229,11 @@ public class HttpUploadConnection implements Transferable {
fail();
}
} catch (IOException e) {
- e.printStackTrace();
- Log.d(Config.LOGTAG,"http upload failed "+e.getMessage());
+ Logging.d(Config.LOGTAG, e.getMessage());
fail();
} finally {
- FileBackend.close(mFileInputStream);
- FileBackend.close(os);
+ StreamUtil.close(is);
+ StreamUtil.close(os);
if (connection != null) {
connection.disconnect();
}
diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
index 7d399073..d825543c 100644
--- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.parser;
+import android.util.Log;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -21,6 +22,15 @@ public abstract class AbstractParser {
this.mXmppConnectionService = service;
}
+ /**
+ * Gets the timestamp from the 'delay' element.
+ * Refer to XEP-0203: Delayed Delivery for details. @link{http://xmpp.org/extensions/xep-0203.html}
+ * @param element the element to find the child element 'delay' in.
+ * @return the time in milli seconds of the attribute 'stamp' of the
+ * element 'delay'. In case there is no 'delay' element or no 'stamp'
+ * attribute or the current time is less than the value of the 'stamp'
+ * attribute the current time is returned.
+ */
public static Long getTimestamp(Element element, Long defaultValue) {
Element delay = element.findChild("delay","urn:xmpp:delay");
if (delay != null) {
@@ -40,12 +50,27 @@ public abstract class AbstractParser {
return getTimestamp(packet,System.currentTimeMillis());
}
+ /**
+ * Parses the timestamp according to XEP-0082: XMPP Date and Time Profiles.
+ * @link{http://xmpp.org/extensions/xep-0082.html}
+ *
+ * @param timestamp the timestamp to parse
+ * @return Date
+ * @throws ParseException
+ */
public static Date parseTimestamp(String timestamp) throws ParseException {
- timestamp = timestamp.replace("Z", "+0000");
- SimpleDateFormat dateFormat;
- timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
- dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
- return dateFormat.parse(timestamp);
+ /*try {
+ Logging.d("TIMESTAMP", timestamp);
+ return DatatypeFactory.newInstance().newXMLGregorianCalendar(timestamp).toGregorianCalendar().getTime();
+ } catch (DatatypeConfigurationException e) {
+ Logging.d("TIMESTAMP", e.getMessage());
+ return new Date();
+ }*/
+ timestamp = timestamp.replace("Z", "+0000");
+ SimpleDateFormat dateFormat;
+ timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
+ dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
+ return dateFormat.parse(timestamp);
}
protected void updateLastseen(final AbstractStanza packet, final Account account, final boolean presenceOverwrite) {
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index 1761e0df..4406a28a 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -23,10 +23,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element;
@@ -70,7 +73,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
contact.parseSubscriptionFromElement(item);
}
}
- mXmppConnectionService.getAvatarService().clear(contact);
+ AvatarService.getInstance().clear(contact);
}
}
mXmppConnectionService.updateConversationUi();
@@ -281,7 +284,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
} else if ((packet.hasChild("block", Xmlns.BLOCKING) || packet.hasChild("blocklist", Xmlns.BLOCKING)) &&
packet.fromServer(account)) {
// Block list or block push.
- Log.d(Config.LOGTAG, "Received blocklist update from server");
+ Logging.d(Config.LOGTAG, "Received blocklist update from server");
final Element blocklist = packet.findChild("blocklist", Xmlns.BLOCKING);
final Element block = packet.findChild("block", Xmlns.BLOCKING);
final Collection<Element> items = blocklist != null ? blocklist.getChildren() :
@@ -309,7 +312,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
mXmppConnectionService.updateBlocklistUi(OnUpdateBlocklist.Status.BLOCKED);
} else if (packet.hasChild("unblock", Xmlns.BLOCKING) &&
packet.fromServer(account) && packet.getType() == IqPacket.TYPE.SET) {
- Log.d(Config.LOGTAG, "Received unblock update from server");
+ Logging.d(Config.LOGTAG, "Received unblock update from server");
final Collection<Element> items = packet.findChild("unblock", Xmlns.BLOCKING).getChildren();
if (items.size() == 0) {
// No children to unblock == unblock all
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index d8eae969..99354100 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -9,6 +9,9 @@ import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
import java.util.Set;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -20,6 +23,7 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.http.HttpConnectionManager;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -182,23 +186,23 @@ public class MessageParser extends AbstractParser implements
Avatar avatar = Avatar.parseMetadata(items);
if (avatar != null) {
avatar.owner = from.toBareJid();
- if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) {
+ if (AvatarUtil.isAvatarCached(avatar)) {
if (account.getJid().toBareJid().equals(from)) {
if (account.setAvatar(avatar.getFilename())) {
mXmppConnectionService.databaseBackend.updateAccount(account);
}
- mXmppConnectionService.getAvatarService().clear(account);
+ AvatarService.getInstance().clear(account);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
} else {
Contact contact = account.getRoster().getContact(from);
contact.setAvatar(avatar);
- mXmppConnectionService.getAvatarService().clear(contact);
+ AvatarService.getInstance().clear(contact);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateRosterUi();
}
} else {
- mXmppConnectionService.fetchAvatar(account, avatar);
+ AvatarService.getInstance().fetchAvatar(account, avatar);
}
}
} else if ("http://jabber.org/protocol/nick".equals(node)) {
@@ -207,7 +211,7 @@ public class MessageParser extends AbstractParser implements
if (nick != null && nick.getContent() != null) {
Contact contact = account.getRoster().getContact(from);
contact.setPresenceName(nick.getContent());
- mXmppConnectionService.getAvatarService().clear(account);
+ AvatarService.getInstance().clear(account);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
}
@@ -273,7 +277,7 @@ public class MessageParser extends AbstractParser implements
serverMsgId = result.getAttribute("id");
query.incrementTotalCount();
} else if (query != null) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": received mam result from invalid sender");
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": received mam result from invalid sender");
return;
} else if (original.fromServer(account)) {
Pair<MessagePacket, Long> f;
@@ -417,7 +421,7 @@ public class MessageParser extends AbstractParser implements
mXmppConnectionService.updateConversationUi();
}
- if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) {
+ if (ConversationsPlusPreferences.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) {
ArrayList<String> receiptsNamespaces = new ArrayList<>();
if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
receiptsNamespaces.add("urn:xmpp:chat-markers:0");
@@ -441,11 +445,15 @@ public class MessageParser extends AbstractParser implements
conversation.endOtrIfNeeded();
}
- if (message.getEncryption() == Message.ENCRYPTION_NONE || mXmppConnectionService.saveEncryptedMessages()) {
+ if (message.getEncryption() == Message.ENCRYPTION_NONE || !ConversationsPlusPreferences.dontSaveEncrypted()) {
mXmppConnectionService.databaseBackend.createMessage(message);
}
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
- if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) {
+ if (message.trusted()
+ && message.treatAsDownloadable() != Message.Decision.NEVER
+ && ConversationsPlusPreferences.autoAcceptFileSize() > 0
+ && ConversationsPlusPreferences.autoDownloadFileLink()
+ && mXmppConnectionService.isDownloadAllowedInConnection()) {
manager.createNewDownloadConnection(message);
} else if (!message.isRead()) {
if (query == null) {
diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
index a07b42a9..bbb21c84 100644
--- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
@@ -4,6 +4,8 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
import eu.siacs.conversations.Config;
@@ -15,6 +17,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.generator.PresenceGenerator;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
@@ -39,13 +42,13 @@ public class PresenceParser extends AbstractParser implements
processConferencePresence(packet, mucOptions);
final List<MucOptions.User> tileUserAfter = mucOptions.getUsers(5);
if (!tileUserAfter.equals(tileUserBefore)) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": update tiles for "+conversation.getName());
- mXmppConnectionService.getAvatarService().clear(mucOptions);
+ Loggin.d(Config.LOGTAG,account.getJid().toBareJid()+": update tiles for "+conversation.getName());
+ AvatarService.getInstance().clear(conversation);
}
if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUserCount())) {
- mXmppConnectionService.updateConversationUi();
+ UiUpdateHelper.updateConversationUi();
} else if (mucOptions.online()) {
- mXmppConnectionService.updateMucRosterUi();
+ UiUpdateHelper.updateMucRosterUi();
}
}
}
@@ -172,14 +175,14 @@ public class PresenceParser extends AbstractParser implements
Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
if (avatar != null && !contact.isSelf()) {
avatar.owner = from.toBareJid();
- if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) {
+ if (AvatarUtil.isAvatarCached(avatar)) {
if (contact.setAvatar(avatar)) {
- mXmppConnectionService.getAvatarService().clear(contact);
- mXmppConnectionService.updateConversationUi();
- mXmppConnectionService.updateRosterUi();
+ AvatarService.getInstance().clear(contact);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateRosterUi();
}
} else {
- mXmppConnectionService.fetchAvatar(account, avatar);
+ AvatarService.getInstance().fetchAvatar(account, avatar);
}
}
int sizeBefore = contact.getPresences().size();
@@ -222,7 +225,7 @@ public class PresenceParser extends AbstractParser implements
}
}
}
- mXmppConnectionService.updateRosterUi();
+ UiUpdateHelper.updateRosterUi();
}
@Override
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 77c16f25..79d69348 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -32,6 +32,8 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore;
@@ -44,6 +46,12 @@ import eu.siacs.conversations.entities.Roster;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
@@ -232,7 +240,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID))
).toString();
} catch (InvalidJidException ignored) {
- Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID "
+ Logging.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID "
+ cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID))
+ ": " + ignored + ". Skipping...");
continue;
@@ -257,7 +265,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
cursor.getString(cursor.getColumnIndex(Contact.JID))
).toString();
} catch (InvalidJidException ignored) {
- Log.e(Config.LOGTAG, "Failed to migrate Contact JID "
+ Logging.e(Config.LOGTAG, "Failed to migrate Contact JID "
+ cursor.getString(cursor.getColumnIndex(Contact.JID))
+ ": " + ignored + ". Skipping...");
continue;
@@ -286,7 +294,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
"mobile"
).getDomainpart();
} catch (InvalidJidException ignored) {
- Log.e(Config.LOGTAG, "Failed to migrate Account SERVER "
+ Logging.e(Config.LOGTAG, "Failed to migrate Account SERVER "
+ cursor.getString(cursor.getColumnIndex(Account.SERVER))
+ ": " + ignored + ". Skipping...");
continue;
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 4bdf080c..f242b928 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -30,8 +30,21 @@ import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Environment;
+import android.webkit.MimeTypeMap;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.exceptions.FileCopyException;
+import de.thedevstack.conversationsplus.utils.StreamUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
@@ -81,52 +94,20 @@ public class FileBackend {
}
public static String getConversationsFileDirectory() {
- return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/";
+ return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + ConversationsPlusPreferences.fileTransferFolder() + File.separator;
}
public static String getConversationsImageDirectory() {
- return Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_PICTURES).getAbsolutePath()
- + "/Conversations/";
+ return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + File.separator + ConversationsPlusPreferences.imgTransferFolder() + File.separator;
}
- public Bitmap resize(Bitmap originalBitmap, int size) {
- int w = originalBitmap.getWidth();
- int h = originalBitmap.getHeight();
- if (Math.max(w, h) > size) {
- int scalledW;
- int scalledH;
- if (w <= h) {
- scalledW = (int) (w / ((double) h / size));
- scalledH = size;
- } else {
- scalledW = size;
- scalledH = (int) (h / ((double) w / size));
- }
- Bitmap result = Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true);
- if (originalBitmap != null && !originalBitmap.isRecycled()) {
- originalBitmap.recycle();
- }
- return result;
- } else {
- return originalBitmap;
- }
- }
+ private static String getPrivateFileDirectoryPath() {
+ return ConversationsPlusApplication.getPrivateFilesDir().getAbsolutePath();
+ }
- public static Bitmap rotate(Bitmap bitmap, int degree) {
- if (degree == 0) {
- return bitmap;
- }
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- Matrix mtx = new Matrix();
- mtx.postRotate(degree);
- Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
- if (bitmap != null && !bitmap.isRecycled()) {
- bitmap.recycle();
- }
- return result;
- }
+ private static String getPrivateImageDirectoryPath() {
+ return FileBackend.getPrivateFileDirectoryPath() + File.separator + "Images" + File.separator;
+ }
public boolean useImageAsIs(Uri uri) {
String path = getOriginalPath(uri);
@@ -162,7 +143,7 @@ public class FileBackend {
try {
file.createNewFile();
os = new FileOutputStream(file);
- is = mXmppConnectionService.getContentResolver().openInputStream(uri);
+ is = StreamUtil.openInputStreamFromContentResolver(uri);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
@@ -175,10 +156,11 @@ public class FileBackend {
e.printStackTrace();
throw new FileCopyException(R.string.error_io_exception);
} finally {
- close(os);
- close(is);
+ StreamUtil.close(os);
+ StreamUtil.close(is);
}
- Log.d(Config.LOGTAG, "output file name " + file.getAbsolutePath());
+ Logging.d(Config.LOGTAG, "output file name " + file);
+ return file;
}
public void copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException {
@@ -240,8 +222,8 @@ public class FileBackend {
} catch (NullPointerException e) {
throw new FileCopyException(R.string.error_io_exception);
} finally {
- close(os);
- close(is);
+ StreamUtil.close(os);
+ StreamUtil.close(is);
}
}
@@ -265,41 +247,7 @@ public class FileBackend {
updateFileParams(message);
}
- private int getRotation(File file) {
- return getRotation(Uri.parse("file://"+file.getAbsolutePath()));
- }
-
- private int getRotation(Uri image) {
- InputStream is = null;
- try {
- is = mXmppConnectionService.getContentResolver().openInputStream(image);
- return ExifHelper.getOrientation(is);
- } catch (FileNotFoundException e) {
- return 0;
- } finally {
- close(is);
- }
- }
-
- public Bitmap getThumbnail(Message message, int size, boolean cacheOnly)
- throws FileNotFoundException {
- Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get(message.getUuid());
- if ((thumbnail == null) && (!cacheOnly)) {
- File file = getFile(message);
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = calcSampleSize(file, size);
- Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),options);
- if (fullsize == null) {
- throw new FileNotFoundException();
- }
- thumbnail = resize(fullsize, size);
- thumbnail = rotate(thumbnail, getRotation(file));
- this.mXmppConnectionService.getBitmapCache().put(message.getUuid(),thumbnail);
- }
- return thumbnail;
- }
-
- public Uri getTakePhotoUri() {
+ public static Uri getTakePhotoUri() {
StringBuilder pathBuilder = new StringBuilder();
pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
pathBuilder.append('/');
@@ -312,283 +260,16 @@ public class FileBackend {
return uri;
}
- public Avatar getPepAvatar(Uri image, int size, Bitmap.CompressFormat format) {
- try {
- Avatar avatar = new Avatar();
- Bitmap bm = cropCenterSquare(image, size);
- if (bm == null) {
- return null;
- }
- ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
- Base64OutputStream mBase64OutputSttream = new Base64OutputStream(
- mByteArrayOutputStream, Base64.DEFAULT);
- MessageDigest digest = MessageDigest.getInstance("SHA-1");
- DigestOutputStream mDigestOutputStream = new DigestOutputStream(
- mBase64OutputSttream, digest);
- if (!bm.compress(format, 75, mDigestOutputStream)) {
- return null;
- }
- mDigestOutputStream.flush();
- mDigestOutputStream.close();
- avatar.sha1sum = CryptoHelper.bytesToHex(digest.digest());
- avatar.image = new String(mByteArrayOutputStream.toByteArray());
- return avatar;
- } catch (NoSuchAlgorithmException e) {
- return null;
- } catch (IOException e) {
- return null;
- }
- }
-
- public boolean isAvatarCached(Avatar avatar) {
- File file = new File(getAvatarPath(avatar.getFilename()));
- return file.exists();
- }
-
- public boolean save(Avatar avatar) {
- File file;
- if (isAvatarCached(avatar)) {
- file = new File(getAvatarPath(avatar.getFilename()));
- } else {
- String filename = getAvatarPath(avatar.getFilename());
- file = new File(filename + ".tmp");
- file.getParentFile().mkdirs();
- OutputStream os = null;
- try {
- file.createNewFile();
- os = new FileOutputStream(file);
- MessageDigest digest = MessageDigest.getInstance("SHA-1");
- digest.reset();
- DigestOutputStream mDigestOutputStream = new DigestOutputStream(os, digest);
- mDigestOutputStream.write(avatar.getImageAsBytes());
- mDigestOutputStream.flush();
- mDigestOutputStream.close();
- String sha1sum = CryptoHelper.bytesToHex(digest.digest());
- if (sha1sum.equals(avatar.sha1sum)) {
- file.renameTo(new File(filename));
- } else {
- Log.d(Config.LOGTAG, "sha1sum mismatch for " + avatar.owner);
- file.delete();
- return false;
- }
- } catch (IllegalArgumentException | IOException | NoSuchAlgorithmException e) {
- return false;
- } finally {
- close(os);
- }
- }
- avatar.size = file.length();
- return true;
- }
-
- public String getAvatarPath(String avatar) {
- return mXmppConnectionService.getFilesDir().getAbsolutePath()+ "/avatars/" + avatar;
- }
-
- public Uri getAvatarUri(String avatar) {
- return Uri.parse("file:" + getAvatarPath(avatar));
- }
-
- public Bitmap cropCenterSquare(Uri image, int size) {
- if (image == null) {
- return null;
- }
- InputStream is = null;
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = calcSampleSize(image, size);
- is = mXmppConnectionService.getContentResolver().openInputStream(image);
- if (is == null) {
- return null;
- }
- Bitmap input = BitmapFactory.decodeStream(is, null, options);
- if (input == null) {
- return null;
- } else {
- input = rotate(input, getRotation(image));
- return cropCenterSquare(input, size);
- }
- } catch (SecurityException e) {
- return null; // happens for example on Android 6.0 if contacts permissions get revoked
- } catch (FileNotFoundException e) {
- return null;
- } finally {
- close(is);
- }
- }
-
- public Bitmap cropCenter(Uri image, int newHeight, int newWidth) {
- if (image == null) {
- return null;
- }
- InputStream is = null;
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = calcSampleSize(image, Math.max(newHeight, newWidth));
- is = mXmppConnectionService.getContentResolver().openInputStream(image);
- if (is == null) {
- return null;
- }
- Bitmap source = BitmapFactory.decodeStream(is, null, options);
- if (source == null) {
- return null;
- }
- int sourceWidth = source.getWidth();
- int sourceHeight = source.getHeight();
- float xScale = (float) newWidth / sourceWidth;
- float yScale = (float) newHeight / sourceHeight;
- float scale = Math.max(xScale, yScale);
- float scaledWidth = scale * sourceWidth;
- float scaledHeight = scale * sourceHeight;
- float left = (newWidth - scaledWidth) / 2;
- float top = (newHeight - scaledHeight) / 2;
-
- RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
- Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(dest);
- canvas.drawBitmap(source, null, targetRect, null);
- if (source != null && !source.isRecycled()) {
- source.recycle();
- }
- return dest;
- } catch (SecurityException e) {
- return null; //android 6.0 with revoked permissions for example
- } catch (FileNotFoundException e) {
- return null;
- } finally {
- close(is);
- }
- }
-
- public Bitmap cropCenterSquare(Bitmap input, int size) {
- int w = input.getWidth();
- int h = input.getHeight();
-
- float scale = Math.max((float) size / h, (float) size / w);
-
- float outWidth = scale * w;
- float outHeight = scale * h;
- float left = (size - outWidth) / 2;
- float top = (size - outHeight) / 2;
- RectF target = new RectF(left, top, left + outWidth, top + outHeight);
-
- Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- canvas.drawBitmap(input, null, target, null);
- if (input != null && !input.isRecycled()) {
- input.recycle();
- }
- return output;
- }
-
- private int calcSampleSize(Uri image, int size) throws FileNotFoundException, SecurityException {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(image), null, options);
- return calcSampleSize(options, size);
- }
-
- private static int calcSampleSize(File image, int size) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(image.getAbsolutePath(), options);
- return calcSampleSize(options, size);
- }
-
- public static int calcSampleSize(BitmapFactory.Options options, int size) {
- int height = options.outHeight;
- int width = options.outWidth;
- int inSampleSize = 1;
-
- if (height > size || width > size) {
- int halfHeight = height / 2;
- int halfWidth = width / 2;
-
- while ((halfHeight / inSampleSize) > size
- && (halfWidth / inSampleSize) > size) {
- inSampleSize *= 2;
- }
- }
- return inSampleSize;
- }
-
- public Uri getJingleFileUri(Message message) {
+ public static Uri getJingleFileUri(Message message) {
File file = getFile(message);
return Uri.parse("file://" + file.getAbsolutePath());
}
- public void updateFileParams(Message message) {
- updateFileParams(message,null);
- }
-
- public void updateFileParams(Message message, URL url) {
- DownloadableFile file = getFile(message);
- if (message.getType() == Message.TYPE_IMAGE || file.getMimeType().startsWith("image/")) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(file.getAbsolutePath(), options);
- int rotation = getRotation(file);
- boolean rotated = rotation == 90 || rotation == 270;
- int imageHeight = rotated ? options.outWidth : options.outHeight;
- int imageWidth = rotated ? options.outHeight : options.outWidth;
- if (url == null) {
- message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight);
- } else {
- message.setBody(url.toString()+"|"+Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight);
- }
- } else {
- if (url != null) {
- message.setBody(url.toString()+"|"+Long.toString(file.getSize()));
- } else {
- message.setBody(Long.toString(file.getSize()));
- }
- }
-
- }
-
- public class FileCopyException extends Exception {
- private static final long serialVersionUID = -1010013599132881427L;
- private int resId;
-
- public FileCopyException(int resId) {
- this.resId = resId;
- }
-
- public int getResId() {
- return resId;
- }
- }
-
- public Bitmap getAvatar(String avatar, int size) {
- if (avatar == null) {
- return null;
- }
- Bitmap bm = cropCenter(getAvatarUri(avatar), size, size);
- if (bm == null) {
- return null;
- }
- return bm;
- }
-
- public boolean isFileAvailable(Message message) {
+ public static boolean isFileAvailable(Message message) {
return getFile(message).exists();
}
- public static void close(Closeable stream) {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
-
- public static void close(Socket socket) {
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- }
- }
- }
+ private FileBackend() {
+ // Static helper class
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
index 8d02f975..d4626fc9 100644
--- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
@@ -32,6 +32,7 @@ import javax.crypto.spec.SecretKeySpec;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.DownloadableFile;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
public class AbstractConnectionManager {
protected XmppConnectionService mXmppConnectionService;
diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java
index 276be10d..1308f32b 100644
--- a/src/main/java/eu/siacs/conversations/services/AvatarService.java
+++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java
@@ -8,9 +8,21 @@ import android.graphics.Typeface;
import android.net.Uri;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
@@ -18,7 +30,14 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.generator.IqGenerator;
+import eu.siacs.conversations.persistance.DatabaseBackend;
+import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnIqPacketReceived;
+import eu.siacs.conversations.xmpp.pep.Avatar;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public class AvatarService {
@@ -30,31 +49,31 @@ public class AvatarService {
private static final String PREFIX_CONVERSATION = "conversation";
private static final String PREFIX_ACCOUNT = "account";
private static final String PREFIX_GENERIC = "generic";
+ private static final AvatarService INSTANCE = new AvatarService();
- final private ArrayList<Integer> sizes = new ArrayList<>();
-
- protected XmppConnectionService mXmppConnectionService = null;
-
- public AvatarService(XmppConnectionService service) {
- this.mXmppConnectionService = service;
- }
+ final private ArrayList<Integer> sizes = new ArrayList<>();
+ private final List<String> mInProgressAvatarFetches = new ArrayList<>();
+
+ public static AvatarService getInstance() {
+ return INSTANCE;
+ }
private Bitmap get(final Contact contact, final int size, boolean cachedOnly) {
final String KEY = key(contact, size);
- Bitmap avatar = this.mXmppConnectionService.getBitmapCache().get(KEY);
+ Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
if (avatar != null || cachedOnly) {
return avatar;
}
if (contact.getProfilePhoto() != null) {
- avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
+ avatar = ImageUtil.cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
}
if (avatar == null && contact.getAvatar() != null) {
- avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatar(), size);
+ avatar = AvatarUtil.getAvatar(contact.getAvatar(), size);
}
if (avatar == null) {
avatar = get(contact.getDisplayName(), size, cachedOnly);
}
- this.mXmppConnectionService.getBitmapCache().put(KEY, avatar);
+ ImageUtil.addBitmapToCache(KEY, avatar);
return avatar;
}
@@ -91,8 +110,7 @@ public class AvatarService {
public void clear(Contact contact) {
synchronized (this.sizes) {
for (Integer size : sizes) {
- this.mXmppConnectionService.getBitmapCache().remove(
- key(contact, size));
+ ImageUtil.removeBitmapFromCache(key(contact, size));
}
}
}
@@ -158,7 +176,7 @@ public class AvatarService {
private Bitmap get(MucOptions mucOptions, int size, boolean cachedOnly) {
final String KEY = key(mucOptions, size);
- Bitmap bitmap = this.mXmppConnectionService.getBitmapCache().get(KEY);
+ Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
if (bitmap != null || cachedOnly) {
return bitmap;
}
@@ -195,14 +213,14 @@ public class AvatarService {
drawTile(canvas, "\u2026", PLACEHOLDER_COLOR, size / 2 + 1, size / 2 + 1,
size, size);
}
- this.mXmppConnectionService.getBitmapCache().put(KEY, bitmap);
+ ImageUtil.addBitmapToCache(KEY, bitmap);
return bitmap;
}
public void clear(MucOptions options) {
synchronized (this.sizes) {
for (Integer size : sizes) {
- this.mXmppConnectionService.getBitmapCache().remove(key(options, size));
+ ImageUtil.removeBitmapFromCache(key(options, size));
}
}
}
@@ -223,16 +241,15 @@ public class AvatarService {
public Bitmap get(Account account, int size, boolean cachedOnly) {
final String KEY = key(account, size);
- Bitmap avatar = mXmppConnectionService.getBitmapCache().get(KEY);
+ Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
if (avatar != null || cachedOnly) {
return avatar;
}
- avatar = mXmppConnectionService.getFileBackend().getAvatar(
- account.getAvatar(), size);
+ avatar = AvatarUtil.getAvatar(account.getAvatar(), size);
if (avatar == null) {
avatar = get(account.getJid().toBareJid().toString(), size,false);
}
- mXmppConnectionService.getBitmapCache().put(KEY, avatar);
+ ImageUtil.addBitmapToCache(KEY, avatar);
return avatar;
}
@@ -257,7 +274,7 @@ public class AvatarService {
public void clear(Account account) {
synchronized (this.sizes) {
for (Integer size : sizes) {
- this.mXmppConnectionService.getBitmapCache().remove(key(account, size));
+ ImageUtil.removeBitmapFromCache(key(account, size));
}
}
}
@@ -286,7 +303,7 @@ public class AvatarService {
public Bitmap get(final String name, final int size, boolean cachedOnly) {
final String KEY = key(name, size);
- Bitmap bitmap = mXmppConnectionService.getBitmapCache().get(KEY);
+ Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
if (bitmap != null || cachedOnly) {
return bitmap;
}
@@ -294,7 +311,7 @@ public class AvatarService {
Canvas canvas = new Canvas(bitmap);
final String trimmedName = name.trim();
drawTile(canvas, trimmedName, 0, 0, size, size);
- mXmppConnectionService.getBitmapCache().put(KEY, bitmap);
+ ImageUtil.addBitmapToCache(KEY, bitmap);
return bitmap;
}
@@ -335,8 +352,7 @@ public class AvatarService {
if (contact.getProfilePhoto() != null) {
uri = Uri.parse(contact.getProfilePhoto());
} else if (contact.getAvatar() != null) {
- uri = mXmppConnectionService.getFileBackend().getAvatarUri(
- contact.getAvatar());
+ uri = AvatarUtil.getAvatarUri(contact.getAvatar());
}
if (drawTile(canvas, uri, left, top, right, bottom)) {
return true;
@@ -393,4 +409,221 @@ public class AvatarService {
canvas.drawBitmap(bm, null, dst, null);
return true;
}
+
+ 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;
+ final Avatar avatar = AvatarUtil.getPepAvatar(image, size, format);
+ if (avatar != null) {
+ avatar.height = size;
+ avatar.width = size;
+ if (format.equals(Bitmap.CompressFormat.WEBP)) {
+ avatar.type = "image/webp";
+ } else if (format.equals(Bitmap.CompressFormat.JPEG)) {
+ avatar.type = "image/jpeg";
+ } else if (format.equals(Bitmap.CompressFormat.PNG)) {
+ avatar.type = "image/png";
+ }
+ if (!AvatarUtil.save(avatar)) {
+ callback.error(R.string.error_saving_avatar, avatar);
+ return;
+ }
+ final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket result) {
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarMetadataPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account,
+ IqPacket result) {
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ if (account.setAvatar(avatar.getFilename())) {
+ AvatarService.getInstance().clear(account);
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ callback.success(avatar);
+ } else {
+ callback.error(
+ R.string.error_publish_avatar_server_reject,
+ avatar);
+ }
+ }
+ });
+ } else {
+ callback.error(
+ R.string.error_publish_avatar_server_reject,
+ avatar);
+ }
+ }
+ });
+ } else {
+ callback.error(R.string.error_publish_avatar_converting, null);
+ }
+ }
+
+ private static String generateFetchKey(Account account, final Avatar avatar) {
+ return account.getJid().toBareJid()+"_"+avatar.owner+"_"+avatar.sha1sum;
+ }
+
+ public void fetchAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ final String KEY = generateFetchKey(account, avatar);
+ synchronized(this.mInProgressAvatarFetches) {
+ if (this.mInProgressAvatarFetches.contains(KEY)) {
+ return;
+ } else {
+ switch (avatar.origin) {
+ case PEP:
+ this.mInProgressAvatarFetches.add(KEY);
+ fetchAvatarPep(account, avatar, callback);
+ break;
+ case VCARD:
+ this.mInProgressAvatarFetches.add(KEY);
+ fetchAvatarVcard(account, avatar, callback);
+ break;
+ }
+ }
+ }
+ }
+
+ private void fetchAvatarPep(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket result) {
+ synchronized (mInProgressAvatarFetches) {
+ mInProgressAvatarFetches.remove(generateFetchKey(account, avatar));
+ }
+ final String ERROR = account.getJid().toBareJid()
+ + ": fetching avatar for " + avatar.owner + " failed ";
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ avatar.image = AvatarPacketParser.parseAvatarData(result);
+ if (avatar.image != null) {
+ if (AvatarUtil.save(avatar)) {
+ if (account.getJid().toBareJid().equals(avatar.owner)) {
+ if (account.setAvatar(avatar.getFilename())) {
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ AvatarService.this.clear(account);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateAccountUi();
+ } else {
+ Contact contact = account.getRoster()
+ .getContact(avatar.owner);
+ contact.setAvatar(avatar);
+ AvatarService.this.clear(contact);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateRosterUi();
+ }
+ if (callback != null) {
+ callback.success(avatar);
+ }
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ + ": succesfuly fetched pep avatar for " + avatar.owner);
+ return;
+ }
+ } else {
+
+ Logging.d(Config.LOGTAG, ERROR + "(parsing error)");
+ }
+ } else {
+ Element error = result.findChild("error");
+ if (error == null) {
+ Logging.d(Config.LOGTAG, ERROR + "(server error)");
+ } else {
+ Logging.d(Config.LOGTAG, ERROR + error.toString());
+ }
+ }
+ if (callback != null) {
+ callback.error(0, null);
+ }
+
+ }
+ });
+ }
+
+ private void fetchAvatarVcard(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ IqPacket packet = IqGenerator.retrieveVcardAvatar(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ synchronized (mInProgressAvatarFetches) {
+ mInProgressAvatarFetches.remove(generateFetchKey(account, avatar));
+ }
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Element vCard = packet.findChild("vCard", "vcard-temp");
+ Element photo = vCard != null ? vCard.findChild("PHOTO") : null;
+ String image = photo != null ? photo.findChildContent("BINVAL") : null;
+ if (image != null) {
+ avatar.image = image;
+ if (AvatarUtil.save(avatar)) {
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ + ": successfully fetched vCard avatar for " + avatar.owner);
+ Contact contact = account.getRoster()
+ .getContact(avatar.owner);
+ contact.setAvatar(avatar);
+ AvatarService.this.clear(contact);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateRosterUi();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
+ IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
+ XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Element pubsub = packet.findChild("pubsub",
+ "http://jabber.org/protocol/pubsub");
+ if (pubsub != null) {
+ Element items = pubsub.findChild("items");
+ if (items != null) {
+ Avatar avatar = Avatar.parseMetadata(items);
+ if (avatar != null) {
+ avatar.owner = account.getJid().toBareJid();
+ if (AvatarUtil.isAvatarCached(avatar)) {
+ if (account.setAvatar(avatar.getFilename())) {
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ AvatarService.this.clear(account);
+ callback.success(avatar);
+ } else {
+ fetchAvatarPep(account, avatar, callback);
+ }
+ return;
+ }
+ }
+ }
+ }
+ callback.error(0, null);
+ }
+ });
+ }
+
+ public void fetchAvatar(Account account, Avatar avatar) {
+ fetchAvatar(account, avatar, null);
+ }
+
+ public void clearFetchInProgress(Account account) {
+ synchronized (this.mInProgressAvatarFetches) {
+ for(Iterator<String> iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext();) {
+ final String KEY = iterator.next();
+ if (KEY.startsWith(account.getJid().toBareJid()+"_")) {
+ iterator.remove();
+ }
+ }
+ }
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
index 4403f99c..4400105e 100644
--- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
+++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java
@@ -9,6 +9,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -127,7 +129,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
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());
+ Logging.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
@@ -140,7 +142,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
}
}
} else if (packet.getType() != IqPacket.TYPE.RESULT) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString());
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString());
finalizeQuery(query);
}
}
@@ -159,7 +161,6 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
final Conversation conversation = query.getConversation();
if (conversation != null) {
conversation.sort();
- conversation.setHasMessagesLeftOnServer(query.getMessageCount() > 0);
} else {
for(Conversation tmp : this.mXmppConnectionService.getConversations()) {
if (tmp.getAccount() == query.getAccount()) {
@@ -170,6 +171,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
if (query.hasCallback()) {
query.callback();
} else {
+ conversation.setHasMessagesLeftOnServer(query.getMessageCount() > 0);
this.mXmppConnectionService.updateConversationUi();
}
}
@@ -204,7 +206,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
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");
+ Logging.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages");
if (query.getWith() == null && query.getMessageCount() > 0) {
mXmppConnectionService.getNotificationService().finishBacklog(true);
}
diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java
index cec9a3ef..5a50a8df 100644
--- a/src/main/java/eu/siacs/conversations/services/NotificationService.java
+++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.services;
+import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -9,6 +10,7 @@ import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
+import android.os.PowerManager;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.BigPictureStyle;
@@ -16,6 +18,7 @@ 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 org.json.JSONArray;
import org.json.JSONObject;
@@ -29,6 +32,10 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.tzur.conversations.Settings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -39,6 +46,7 @@ import eu.siacs.conversations.ui.ManageAccountActivity;
import eu.siacs.conversations.ui.TimePreference;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.XmppConnection;
public class NotificationService {
@@ -60,10 +68,13 @@ public class NotificationService {
public boolean notify(final Message message) {
return (message.getStatus() == Message.STATUS_RECEIVED)
- && notificationsEnabled()
- && !message.getConversation().isMuted()
- && (message.getConversation().alwaysNotify() || wasHighlightedOrPrivate(message)
- );
+ && !message.isRead()
+ && ConversationsPlusPreferences.showNotification()
+ && !message.getConversation().isMuted()
+ && (message.getConversation().getMode() == Conversation.MODE_SINGLE
+ || ConversationsPlusPreferences.alwaysNotifyInConference()
+ || wasHighlightedOrPrivate(message)
+ );
}
public void notifyPebble(final Message message) {
@@ -77,7 +88,7 @@ public class NotificationService {
final String notificationData = new JSONArray().put(jsonData).toString();
i.putExtra("messageType", "PEBBLE_ALERT");
- i.putExtra("sender", "Conversations"); /* XXX: Shouldn't be hardcoded, e.g., AbstractGenerator.APP_NAME); */
+ i.putExtra("sender", ConversationsPlusApplication.getName());
i.putExtra("notificationData", notificationData);
// notify Pebble App
i.setPackage("com.getpebble.android");
@@ -93,11 +104,11 @@ public class NotificationService {
}
public boolean isQuietHours() {
- if (!mXmppConnectionService.getPreferences().getBoolean("enable_quiet_hours", false)) {
+ if (!ConversationsPlusPreferences.enableQuietHours()) {
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 startTime = ConversationsPlusPreferences.quietHoursStart() % Config.MILLISECONDS_IN_DAY;
+ final long endTime = ConversationsPlusPreferences.quietHoursEnd() % Config.MILLISECONDS_IN_DAY;
final long nowTime = Calendar.getInstance().getTimeInMillis() % Config.MILLISECONDS_IN_DAY;
if (endTime < startTime) {
@@ -134,10 +145,10 @@ public class NotificationService {
}
public void push(final Message message) {
- mXmppConnectionService.updateUnreadCountBadge();
if (!notify(message)) {
return;
}
+ mXmppConnectionService.updateUnreadCountBadge();
final boolean isScreenOn = mXmppConnectionService.isInteractive();
if (this.mIsInForeground && isScreenOn && this.mOpenConversation == message.getConversation()) {
return;
@@ -174,12 +185,10 @@ public class NotificationService {
}
public void updateNotification(final boolean notify) {
- final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService
- .getSystemService(Context.NOTIFICATION_SERVICE);
- final SharedPreferences preferences = mXmppConnectionService.getPreferences();
+ final NotificationManager notificationManager = (NotificationManager) ConversationsPlusApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
- final String ringtone = preferences.getString("notification_ringtone", null);
- final boolean vibrate = preferences.getBoolean("vibrate_on_notification", true);
+ final String ringtone = ConversationsPlusPreferences.notificationRingtone();
+ final boolean vibrate = ConversationsPlusPreferences.vibrateOnNotification();
if (notifications.size() == 0) {
notificationManager.cancel(NOTIFICATION_ID);
@@ -210,7 +219,7 @@ public class NotificationService {
mBuilder.setDefaults(0);
mBuilder.setSmallIcon(R.drawable.ic_notification);
mBuilder.setDeleteIntent(createDeleteIntent());
- mBuilder.setLights(0xff00FF00, 2000, 3000);
+ mBuilder.setLights(Settings.LED_COLOR, 2000, 4000);
final Notification notification = mBuilder.build();
notificationManager.notify(NOTIFICATION_ID, notification);
}
@@ -262,8 +271,7 @@ public class NotificationService {
final ArrayList<Message> messages = notifications.values().iterator().next();
if (messages.size() >= 1) {
final Conversation conversation = messages.get(0).getConversation();
- mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
- .get(conversation, getPixel(64)));
+ mBuilder.setLargeIcon(AvatarService.getInstance().get(conversation, getPixel(64)));
mBuilder.setContentTitle(conversation.getName());
if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
int count = messages.size();
@@ -300,8 +308,7 @@ public class NotificationService {
private void modifyForImage(final Builder builder, final Message message,
final ArrayList<Message> messages, final boolean notify) {
try {
- final Bitmap bitmap = mXmppConnectionService.getFileBackend()
- .getThumbnail(message, getPixel(288), false);
+ final Bitmap bitmap = ImageUtil.getThumbnail(message, getPixel(288), false);
final ArrayList<Message> tmp = new ArrayList<>();
for (final Message msg : messages) {
if (msg.getType() == Message.TYPE_TEXT
@@ -361,7 +368,7 @@ public class NotificationService {
&& message.getEncryption() != Message.ENCRYPTION_PGP
&& message.getFileParams().height > 0) {
return message;
- }
+ }
}
return null;
}
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 99183dff..09a409fc 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -59,6 +59,18 @@ import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import de.duenndns.ssl.MemorizingTrustManager;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.exceptions.FileCopyException;
+import de.thedevstack.conversationsplus.utils.FileHelper;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.tzur.conversations.Settings;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -69,6 +81,8 @@ 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.Transferable;
+import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
@@ -115,12 +129,14 @@ import eu.siacs.conversations.xmpp.pep.Avatar;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
+
import me.leolin.shortcutbadger.ShortcutBadger;
public class XmppConnectionService extends Service implements OnPhoneContactsLoadedListener {
public static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
public static final String ACTION_DISABLE_FOREGROUND = "disable_foreground";
+ private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
public static final String ACTION_TRY_AGAIN = "try_again";
public static final String ACTION_DISABLE_ACCOUNT = "disable_account";
private static final String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
@@ -155,7 +171,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
Element error = packet.findChild("error");
String text = error != null ? error.findChildContent("text") : null;
if (text != null) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": received iq error - " + text);
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": received iq error - " + text);
}
}
}
@@ -269,10 +285,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (account.getStatus() == Account.State.ONLINE) {
if (connection != null && connection.getFeatures().csi()) {
if (checkListeners()) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//inactive");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//inactive");
connection.sendInactive();
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//active");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + " sending csi//active");
connection.sendActive();
}
}
@@ -305,7 +321,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
&& (account.getStatus() != Account.State.NO_INTERNET)) {
if (connection != null) {
int next = connection.getTimeToNextAttempt();
- Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": error connecting account. try again in "
+ next + "s for the "
+ (connection.getAttempt() + 1) + " time");
@@ -384,32 +400,32 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
message.setCounterpart(conversation.getNextCounterpart());
message.setType(Message.TYPE_FILE);
- String path = getFileBackend().getOriginalPath(uri);
+ String path = FileHelper.getRealPathFromUri(uri);
if (path != null) {
message.setRelativeFilePath(path);
- getFileBackend().updateFileParams(message);
+ MessageUtil.updateFileParams(message);
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
getPgpEngine().encrypt(message, callback);
} else {
callback.success(message);
}
} else {
- mFileAddingExecutor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- getFileBackend().copyFileToPrivateStorage(message, uri);
- getFileBackend().updateFileParams(message);
- if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
- getPgpEngine().encrypt(message, callback);
- } else {
- callback.success(message);
- }
- } catch (FileBackend.FileCopyException e) {
- callback.error(e.getResId(), message);
- }
- }
- });
+ ConversationsPlusApplication.executeFileAdding(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ FileBackend.copyFileToPrivateStorage(message, uri);
+ MessageUtil.updateFileParams(message);
+ if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
+ getPgpEngine().encrypt(message, callback);
+ } else {
+ callback.success(message);
+ }
+ } catch (FileCopyException e) {
+ callback.error(e.getResId(), message);
+ }
+ }
+ });
}
}
@@ -478,7 +494,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mNotificationService.clear();
break;
case ACTION_DISABLE_FOREGROUND:
- getPreferences().edit().putBoolean("keep_foreground_service", false).commit();
+ ConversationsPlusPreferences.commitKeepForegroundService(false);
toggleForegroundService();
break;
case ACTION_TRY_AGAIN:
@@ -534,7 +550,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
long pingTimeoutIn = (lastSent + Config.PING_TIMEOUT * 1000) - SystemClock.elapsedRealtime();
if (lastSent > lastReceived) {
if (pingTimeoutIn < 0) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ping timeout");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": ping timeout");
this.reconnectAccount(account, true, interactive);
} else {
int secs = (int) (pingTimeoutIn / 1000);
@@ -542,7 +558,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
} else if (msToNextPing <= 0) {
account.getXmppConnection().sendPing();
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + " send ping");
this.scheduleWakeUpCall(Config.PING_TIMEOUT, account.getUuid().hashCode());
} else {
this.scheduleWakeUpCall((int) (msToNextPing / 1000), account.getUuid().hashCode());
@@ -555,7 +571,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
long discoTimeout = Config.CONNECT_DISCO_TIMEOUT - secondsSinceLastDisco;
long timeout = Config.CONNECT_TIMEOUT - secondsSinceLastConnect;
if (timeout < 0) {
- Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
+ Logging.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
reconnectAccount(account, true, interactive);
} else if (discoTimeout < 0) {
account.getXmppConnection().sendDiscoTimeout();
@@ -626,7 +642,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
private void resetAllAttemptCounts(boolean reallyAll) {
- Log.d(Config.LOGTAG, "resetting all attepmt counts");
+ Logging.d(Config.LOGTAG, "resetting all attepmt counts");
for (Account account : accounts) {
if (account.hasErrorStatus() || reallyAll) {
final XmppConnection connection = account.getXmppConnection();
@@ -644,6 +660,25 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return activeNetwork != null && activeNetwork.isConnected();
}
+ /**
+ * check whether we are allowed to download at the moment
+ */
+ public boolean isDownloadAllowedInConnection() {
+ if (ConversationsPlusPreferences.autoDownloadFileWLAN()) {
+ return isWifiConnected();
+ }
+ return true;
+ }
+
+ /**
+ * check whether wifi is connected
+ */
+ public boolean isWifiConnected() {
+ ConnectivityManager cm = (ConnectivityManager) ConversationsPlusApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo niWifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ return niWifi.isConnected();
+ }
+
@SuppressLint("TrulyRandom")
@Override
public void onCreate() {
@@ -687,6 +722,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "XmppConnectionService");
toggleForegroundService();
updateUnreadCountBadge();
+ UiUpdateHelper.initXmppConnectionService(this);
toggleScreenEventReceiver();
}
@@ -724,7 +760,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void toggleForegroundService() {
- if (getPreferences().getBoolean("keep_foreground_service", false)) {
+ if (ConversationsPlusPreferences.keepForegroundService()) {
startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification());
} else {
stopForeground(true);
@@ -734,7 +770,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
- if (!getPreferences().getBoolean("keep_foreground_service", false)) {
+ if (!ConversationsPlusPreferences.keepForegroundService()) {
this.logoutAndSave();
}
}
@@ -757,7 +793,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, EventReceiver.class);
alarmManager.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
- Log.d(Config.LOGTAG, "good bye");
+ Logging.d(Config.LOGTAG, "good bye");
stopSelf();
}
@@ -774,9 +810,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public XmppConnection createConnection(final Account account) {
- final SharedPreferences sharedPref = getPreferences();
- account.setResource(sharedPref.getString("resource", "mobile")
- .toLowerCase(Locale.getDefault()));
+ account.setResource(ConversationsPlusPreferences.resource().toLowerCase(Locale.getDefault()));
final XmppConnection connection = new XmppConnection(account, this);
connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
@@ -794,14 +828,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void sendChatState(Conversation conversation) {
- if (sendChatStates()) {
+ if (ConversationsPlusPreferences.chatStates()) {
MessagePacket packet = mMessageGenerator.generateChatState(conversation);
sendMessagePacket(conversation.getAccount(), packet);
}
}
private void sendFileMessage(final Message message, final boolean delay) {
- Log.d(Config.LOGTAG, "send file message");
+ Logging.d(Config.LOGTAG, "send file message");
final Account account = message.getConversation().getAccount();
final XmppConnection connection = account.getXmppConnection();
if (connection != null && connection.getFeatures().httpUpload()) {
@@ -955,7 +989,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mMessageGenerator.addDelay(packet, message.getTimeSent());
}
if (conversation.setOutgoingChatState(Config.DEFAULT_CHATSTATE)) {
- if (this.sendChatStates()) {
+ if (ConversationsPlusPreferences.chatStates()) {
packet.addChild(ChatState.toElement(conversation.getOutgoingChatState()));
}
}
@@ -980,10 +1014,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
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()
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": fetching roster version " + account.getRosterVersion());
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster");
}
iqPacket.query(Xmlns.ROSTER).setAttribute("ver", account.getRosterVersion());
sendIqPacket(account, iqPacket, mIqParser);
@@ -1024,7 +1058,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
account.setBookmarks(new ArrayList<>(bookmarks.values()));
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not fetch bookmarks");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not fetch bookmarks");
}
}
};
@@ -1032,7 +1066,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void pushBookmarks(Account account) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()+": pushing bookmarks");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()+": pushing bookmarks");
IqPacket iqPacket = new IqPacket(IqPacket.TYPE.SET);
Element query = iqPacket.query("jabber:iq:private");
Element storage = query.addChild("storage", "storage:bookmarks");
@@ -1049,12 +1083,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
mPhoneContactMergerThread = new Thread(new Runnable() {
@Override
public void run() {
- Log.d(Config.LOGTAG, "start merging phone contacts with roster");
+ Logging.d(Config.LOGTAG, "start merging phone contacts with roster");
for (Account account : accounts) {
List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts();
for (Bundle phoneContact : phoneContacts) {
if (Thread.interrupted()) {
- Log.d(Config.LOGTAG, "interrupted merging phone contacts");
+ Logging.d(Config.LOGTAG,"interrupted merging phone contacts");
return;
}
Jid jid;
@@ -1069,7 +1103,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
+ phoneContact.getString("lookup");
contact.setSystemAccount(systemAccount);
if (contact.setPhotoUri(phoneContact.getString("photouri"))) {
- getAvatarService().clear(contact);
+ AvatarService.getInstance().clear(contact);
}
contact.setSystemName(phoneContact.getString("displayname"));
withSystemAccounts.remove(contact);
@@ -1078,11 +1112,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
contact.setSystemAccount(null);
contact.setSystemName(null);
if (contact.setPhotoUri(null)) {
- getAvatarService().clear(contact);
+ AvatarService.getInstance().clear(contact);
}
}
}
- Log.d(Config.LOGTAG, "finished merging phone contacts");
+ Logging.d(Config.LOGTAG,"finished merging phone contacts");
updateAccountUi();
}
});
@@ -1103,15 +1137,15 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
Runnable runnable = new Runnable() {
@Override
public void run() {
- Log.d(Config.LOGTAG, "restoring roster");
+ Logging.d(Config.LOGTAG, "restoring roster");
for (Account account : accounts) {
databaseBackend.readRoster(account.getRoster());
account.initAccountServices(XmppConnectionService.this); //roster needs to be loaded at this stage
}
- getBitmapCache().evictAll();
+ ImageUtil.evictBitmapCache();
Looper.prepare();
loadPhoneContacts();
- Log.d(Config.LOGTAG, "restoring messages");
+ Logging.d(Config.LOGTAG, "restoring messages");
for (Conversation conversation : conversations) {
conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE));
checkDeletedFiles(conversation);
@@ -1124,11 +1158,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
mNotificationService.finishBacklog(false);
mRestoredFromDatabase = true;
- Log.d(Config.LOGTAG, "restored all messages");
+ Logging.d(Config.LOGTAG,"restored all messages");
updateConversationUi();
}
};
- mDatabaseExecutor.execute(runnable);
+ ConversationsPlusApplication.executeDatabaseOperation(runnable);
}
}
@@ -1147,7 +1181,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void onMessageFound(Message message) {
- if (!getFileBackend().isFileAvailable(message)) {
+ if (!FileBackend.isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
final int s = message.getStatus();
if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
@@ -1162,7 +1196,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
for (Conversation conversation : getConversations()) {
Message message = conversation.findMessageWithFileAndUuid(uuid);
if (message != null) {
- if (!getFileBackend().isFileAvailable(message)) {
+ if (!FileBackend.isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
final int s = message.getStatus();
if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
@@ -1210,20 +1244,29 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void loadMoreMessages(final Conversation conversation, final long timestamp, final OnMoreMessagesLoaded callback) {
if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation, callback)) {
+ Logging.d("mam", "Query in progress");
return;
}
- Log.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
+ //TODO Create a separate class for this runnable to store if messages are getting loaded or not. Not really a good idea to do this in the callback.
+ Logging.d(Config.LOGTAG, "load more messages for " + conversation.getName() + " prior to " + MessageGenerator.getTimestamp(timestamp));
Runnable runnable = new Runnable() {
@Override
public void run() {
+ if (null == callback || !callback.isLoadingInProgress()) { // if a callback is set, ensure that there is no loading in progress
+ if (null != callback) {
+ callback.setLoadingInProgress(); // Tell the callback that the loading is in progress
+ }
final Account account = conversation.getAccount();
List<Message> messages = databaseBackend.getMessages(conversation, 50, timestamp);
+ Logging.d("mam", "runnable load more messages");
if (messages.size() > 0) {
+ Logging.d("mam", "At least one message");
conversation.addAll(0, messages);
checkDeletedFiles(conversation);
callback.onMoreMessagesLoaded(messages.size(), conversation);
} else if (conversation.hasMessagesLeftOnServer()
&& account.isOnlineAndConnected()) {
+ Logging.d("mam", "mam activate, account online and connected and messages left on server");
if ((conversation.getMode() == Conversation.MODE_SINGLE && account.getXmppConnection().getFeatures().mam())
|| (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().mamSupport())) {
MessageArchiveService.Query query = getMessageArchiveService().query(conversation, 0, timestamp - 1);
@@ -1232,10 +1275,15 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
callback.informUser(R.string.fetching_history_from_server);
}
- }
+ } else {
+ Logging.d("mam", ((!conversation.hasMessagesLeftOnServer()) ? "no" : "") + " more messages left on server, mam " + ((account.getXmppConnection().getFeatures().mam()) ? "" : "not") + " activated, account is " + ((account.isOnlineAndConnected()) ? "" : "not") + " online or connected)");
+ callback.onMoreMessagesLoaded(0, conversation);
+ callback.informUser(R.string.no_more_history_on_server);
+ }
}
+ }
};
- mDatabaseExecutor.execute(runnable);
+ ConversationsPlusApplication.executeDatabaseOperation(runnable);
}
public List<Account> getAccounts() {
@@ -1464,7 +1512,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
databaseBackend.deleteAccount(account);
}
};
- mDatabaseExecutor.execute(runnable);
+ ConversationsPlusApplication.executeDatabaseOperation.execute(runnable);
this.accounts.remove(account);
updateAccountUi();
getNotificationService().updateErrorNotification();
@@ -1696,7 +1744,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
}
- Log.d(Config.LOGTAG, "app switched into foreground");
+ Logging.d(Config.LOGTAG, "app switched into foreground");
}
private void switchToBackground() {
@@ -1709,7 +1757,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
this.mNotificationService.setIsInForeground(false);
- Log.d(Config.LOGTAG, "app switched into background");
+ Logging.d(Config.LOGTAG, "app switched into background");
}
private void connectMultiModeConversations(Account account) {
@@ -1867,7 +1915,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
sendPresencePacket(conversation.getAccount(), packet);
conversation.getMucOptions().setOffline();
conversation.deregisterWithBookmark();
- Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()
+ Logging.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid()
+ ": leaving muc " + conversation.getJid());
} else {
account.pendingConferenceLeaves.add(conversation);
@@ -1894,7 +1942,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
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());
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": creating adhoc conference with " + jids.toString());
if (account.getStatus() == Account.State.ONLINE) {
try {
String server = findConferenceServer(account);
@@ -2069,11 +2117,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void changeRoleInConference(final Conversation conference, final String nick, MucOptions.Role role, final OnRoleChanged callback) {
IqPacket request = this.mIqGenerator.changeRole(conference, nick, role.toString());
- Log.d(Config.LOGTAG, request.toString());
+ Logging.d(Config.LOGTAG, request.toString());
sendIqPacket(conference.getAccount(), request, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- Log.d(Config.LOGTAG, packet.toString());
+ Logging.d(Config.LOGTAG, packet.toString());
if (packet.getType() == IqPacket.TYPE.RESULT) {
callback.onRoleChangedSuccessful(nick);
} else {
@@ -2094,7 +2142,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
leaveMuc(conversation, true);
} else {
if (conversation.endOtrIfNeeded()) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": ended otr session with "
+ conversation.getJid());
}
@@ -2129,8 +2177,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void createContact(Contact contact) {
- boolean autoGrant = getPreferences().getBoolean("grant_new_contacts", true);
- if (autoGrant) {
+ if (ConversationsPlusPreferences.grantNewContacts()) {
contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
contact.setOption(Contact.Options.ASKING);
}
@@ -2140,7 +2187,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void onOtrSessionEstablished(Conversation conversation) {
final Account account = conversation.getAccount();
final Session otrSession = conversation.getOtrSession();
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
account.getJid().toBareJid() + " otr session established with "
+ conversation.getJid() + "/"
+ otrSession.getSessionID().getUserID());
@@ -2472,7 +2519,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
if (!force) {
try {
- Log.d(Config.LOGTAG, "wait for disconnect");
+ Logging.d(Config.LOGTAG, "wait for disconnect");
Thread.sleep(500); //sleep wait for disconnect
} catch (InterruptedException e) {
//ignored
@@ -2499,7 +2546,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
public void invite(Conversation conversation, Jid contact) {
- Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": inviting " + contact + " to " + conversation.getJid().toBareJid());
+ Logging.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": inviting " + contact + " to " + conversation.getJid().toBareJid());
MessagePacket packet = mMessageGenerator.invite(conversation, contact);
sendMessagePacket(conversation.getAccount(), packet);
}
@@ -2692,7 +2739,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
};
- mDatabaseExecutor.execute(runnable);
+ ConversationsPlusApplication.executeDatabaseOperation.execute(runnable);
}
updateUnreadCountBadge();
}
@@ -2700,7 +2747,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public synchronized void updateUnreadCountBadge() {
int count = unreadCount();
if (unreadCount != count) {
- Log.d(Config.LOGTAG, "update unread count to " + count);
+ Logging.d(Config.LOGTAG, "update unread count to " + count);
if (count > 0) {
ShortcutBadger.with(getApplicationContext()).count(count);
} else {
@@ -2713,8 +2760,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
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());
+ if (Settings.CONFIRM_MESSAGE_READ && markable != null && markable.getRemoteMsgId() != null) {
+ Logging.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());
@@ -2737,9 +2784,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void updateMemorizingTrustmanager() {
final MemorizingTrustManager tm;
- final boolean dontTrustSystemCAs = getPreferences().getBoolean("dont_trust_system_cas", false);
- if (dontTrustSystemCAs) {
- tm = new MemorizingTrustManager(getApplicationContext(), null);
+ if (ConversationsPlusPreferences.dontTrustSystemCAs()) {
+ tm = new MemorizingTrustManager(getApplicationContext(), null);
} else {
tm = new MemorizingTrustManager(getApplicationContext());
}
@@ -2762,8 +2808,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
databaseBackend.writeRoster(account.getRoster());
}
};
- mDatabaseExecutor.execute(runnable);
-
+ ConversationsPlusApplication.executeDatabaseOperation(runnable);
}
public List<String> getKnownHosts() {
@@ -2906,14 +2951,19 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void clearConversationHistory(final Conversation conversation) {
conversation.clearMessages();
- conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam
+ /*
+ * In case the history was loaded completely before.
+ * The flag "hasMessagesLeftOnServer" is set to false and no messages will be loaded anymore
+ * Therefore set this flag to true and try to get messages from server
+ */
+ conversation.setHasMessagesLeftOnServer(true);
Runnable runnable = new Runnable() {
@Override
public void run() {
databaseBackend.deleteMessagesInConversation(conversation);
}
};
- mDatabaseExecutor.execute(runnable);
+ ConversationsPlusPreferences.dontTrustSystemCAs().execute(runnable);
}
public void sendBlockRequest(final Blockable blockable) {
diff --git a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
index bd2042fb..b9e5c367 100644
--- a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
+++ b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java
@@ -5,7 +5,7 @@ import android.content.Intent;
import android.preference.Preference;
import android.util.AttributeSet;
-import eu.siacs.conversations.utils.PhoneHelper;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
public class AboutPreference extends Preference {
public AboutPreference(final Context context, final AttributeSet attrs, final int defStyle) {
@@ -26,7 +26,7 @@ public class AboutPreference extends Preference {
}
private void setSummary() {
- setSummary("Conversations " + PhoneHelper.getVersionName(getContext()));
+ setSummary(ConversationsPlusApplication.getNameAndVersion());
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
index ccb3a22e..f55c99f3 100644
--- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java
@@ -26,11 +26,14 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
mCurrentPassword.requestFocus();
mCurrentPassword.setError(getString(R.string.account_status_unauthorized));
} else if (!newPassword.equals(newPasswordConfirm)) {
- mNewPasswordConfirm.requestFocus();
- mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
+ mNewPasswordConfirm.requestFocus();
+ mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
+ } else if (newPassword.isEmpty()) {
+ mNewPassword.requestFocus();
+ mNewPassword.setError(getString(R.string.password_should_not_be_empty));
} else if (newPassword.trim().isEmpty()) {
mNewPassword.requestFocus();
- mNewPassword.setError(getString(R.string.password_should_not_be_empty));
+ mNewPassword.setError(getString(R.string.password_should_not_contain_only_spaces));
} else {
mCurrentPassword.setError(null);
mNewPassword.setError(null);
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index be454936..e42d3e61 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -39,6 +39,7 @@ import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.User;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate;
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index f8d1c97f..2a8bb1ce 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -35,6 +35,9 @@ import org.openintents.openpgp.util.OpenPgpUtils;
import java.security.cert.X509Certificate;
import java.util.List;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -221,8 +224,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
getActionBar().setDisplayHomeAsUpEnabled(true);
}
- final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
+ this.showDynamicTags = ConversationsPlusPreferences.showDynamicTags();
}
@Override
@@ -370,8 +372,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
} else {
account = contact.getAccount().getJid().toBareJid().toString();
}
+ contactJidTv.setOnClickListener(new ShowResourcesListDialogListener(ContactDetailsActivity.this, contact));
accountJidTv.setText(getString(R.string.using_account, account));
- badge.setImageBitmap(avatarService().get(contact, getPixel(72)));
+ badge.setImageBitmap(AvatarService.getInstance().get(contact, getPixel(72)));
badge.setOnClickListener(this.onBadgeClick);
keys.removeAllViews();
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index b4857067..1f163b82 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -36,6 +36,10 @@ import android.widget.Toast;
import net.java.otr4j.session.SessionStatus;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog;
+import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener;
+import de.timroes.android.listview.EnhancedListView;
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.ArrayList;
@@ -54,6 +58,7 @@ import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
@@ -273,6 +278,7 @@ public class ConversationActivity extends XmppActivity
}
});
listView.enableSwipeToDismiss();
+ listView.setSwipeDirection(EnhancedListView.SwipeDirection.START);
listView.setSwipingLayout(R.id.swipeable_item);
listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
listView.setUndoHideDelay(5000);
@@ -284,9 +290,10 @@ public class ConversationActivity extends XmppActivity
}
if (mContentView instanceof SlidingPaneLayout) {
SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ // Move the conversation list when sliding the selected conversation
mSlidingPaneLayout.setParallaxDistance(150);
- mSlidingPaneLayout
- .setShadowResource(R.drawable.es_slidingpane_shadow);
+ // The shadow between conversation list and selected conversation
+ mSlidingPaneLayout.setShadowResourceLeft(R.drawable.es_slidingpane_shadow);
mSlidingPaneLayout.setSliderFadeColor(0);
mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
@@ -340,7 +347,7 @@ public class ConversationActivity extends XmppActivity
if (titleShouldBeName && conversation != null) {
ab.setDisplayHomeAsUpEnabled(true);
ab.setHomeButtonEnabled(true);
- if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE || ConversationsPlusPreferences.useSubject()) {
ab.setTitle(conversation.getName());
} else {
ab.setTitle(conversation.getJid().toBareJid().toString());
@@ -446,7 +453,7 @@ public class ConversationActivity extends XmppActivity
chooser = true;
break;
case ATTACHMENT_CHOICE_TAKE_PHOTO:
- Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
+ Uri uri = FileBackend.getTakePhotoUri();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
mPendingImageUris.clear();
@@ -507,16 +514,16 @@ public class ConversationActivity extends XmppActivity
}
switch (attachmentChoice) {
case ATTACHMENT_CHOICE_LOCATION:
- getPreferences().edit().putString("recently_used_quick_action", "location").apply();
+ ConversationsPlusPreferences.applyRecentlyUsedQuickAction("location");
break;
case ATTACHMENT_CHOICE_RECORD_VOICE:
- getPreferences().edit().putString("recently_used_quick_action", "voice").apply();
+ ConversationsPlusPreferences.applyRecentlyUsedQuickAction("voice");
break;
case ATTACHMENT_CHOICE_TAKE_PHOTO:
- getPreferences().edit().putString("recently_used_quick_action", "photo").apply();
+ ConversationsPlusPreferences.applyRecentlyUsedQuickAction("photo");
break;
case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
- getPreferences().edit().putString("recently_used_quick_action", "picture").apply();
+ ConversationsPlusPreferences.applyRecentlyUsedQuickAction("picture");
break;
}
final Conversation conversation = getSelectedConversation();
@@ -1072,7 +1079,7 @@ public class ConversationActivity extends XmppActivity
public void onResume() {
super.onResume();
final int theme = findTheme();
- final boolean usingEnterKey = usingEnterKey();
+ final boolean usingEnterKey = ConversationsPlusPreferences.displayEnterKey();
if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) {
recreate();
}
@@ -1339,51 +1346,13 @@ public class ConversationActivity extends XmppActivity
}
} else {
- mPendingImageUris.clear();
- mPendingFileUris.clear();
- if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) {
- mConversationFragment.onActivityResult(requestCode, resultCode, data);
- }
- if (requestCode == REQUEST_BATTERY_OP) {
- setNeverAskForBatteryOptimizationsAgain();
+ if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
+ mPendingImageUri = null;
}
}
}
- private void setNeverAskForBatteryOptimizationsAgain() {
- getPreferences().edit().putBoolean("show_battery_optimization", false).commit();
- }
-
- private void openBatteryOptimizationDialogIfNeeded() {
- if (showBatteryOptimizationWarning() && getPreferences().getBoolean("show_battery_optimization", true)) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.battery_optimizations_enabled);
- builder.setMessage(R.string.battery_optimizations_enabled_dialog);
- builder.setPositiveButton(R.string.next, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- Uri uri = Uri.parse("package:" + getPackageName());
- intent.setData(uri);
- startActivityForResult(intent, REQUEST_BATTERY_OP);
- }
- });
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- setNeverAskForBatteryOptimizationsAgain();
- }
- });
- }
- builder.create().show();
- }
- }
-
private void attachLocationToConversation(Conversation conversation, Uri uri) {
- if (conversation == null) {
- return;
- }
xmppConnectionService.attachLocationToConversation(conversation,uri, new UiCallback<Message>() {
@Override
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index c23c20f4..568189a8 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -29,12 +29,16 @@ import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
+import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout;
+
import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
@@ -43,6 +47,10 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.ui.dialogs.MessageDetailsDialog;
+
+import eu.siacs.conversations.ui.listeners.ConversationSwipeRefreshListener;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -50,22 +58,27 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.DownloadableFile;
+import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presences;
-import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.entities.TransferablePlaceholder;
+import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
import eu.siacs.conversations.ui.adapter.MessageAdapter;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
+import eu.siacs.conversations.ui.listeners.ConversationSwipeRefreshListener;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
import eu.siacs.conversations.xmpp.jid.Jid;
+import github.ankushsachdeva.emojicon.EmojiconGridView;
+import github.ankushsachdeva.emojicon.EmojiconsPopup;
+import github.ankushsachdeva.emojicon.emoji.Emojicon;
public class ConversationFragment extends Fragment implements EditMessage.KeyboardListener {
@@ -104,10 +117,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
};
protected ListView messagesView;
+ protected SwipyRefreshLayout swipeLayout;
final protected List<Message> messageList = new ArrayList<>();
protected MessageAdapter messageListAdapter;
private EditMessage mEditMessage;
private ImageButton mSendButton;
+ private ImageView mEmojButton;
+ private View mRootView;
+ private EmojiconsPopup mEmojPopup;
private RelativeLayout snackbar;
private TextView snackbarMessage;
private TextView snackbarAction;
@@ -384,7 +401,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
public void setupIme() {
if (activity == null) {
return;
- } else if (activity.usingEnterKey() && activity.enterIsSend()) {
+ } else if (activity.usingEnterKey() && ConversationsPlusPreferences.enterIsSend()) {
mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE));
mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE));
} else if (activity.usingEnterKey()) {
@@ -412,6 +429,107 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
});
mEditMessage.setOnEditorActionListener(mEditorActionListener);
+ // Start of emojicon
+ mEmojButton = (ImageView) view.findViewById(R.id.emoji_btn);
+ mRootView = view.findViewById(R.id.textsend);
+
+ // Give the topmost view of your activity layout hierarchy. This will be used to measure soft keyboard height
+ mEmojPopup = new EmojiconsPopup(mRootView, this.getActivity());
+
+ //Will automatically set size according to the soft keyboard size
+ mEmojPopup.setSizeForSoftKeyboard();
+
+ //If the emoji popup is dismissed, change emojiButton to smiley icon
+ mEmojPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
+
+ @Override
+ public void onDismiss() {
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.smiley);
+ }
+ });
+
+ //If the text keyboard closes, also dismiss the emoji popup
+ mEmojPopup.setOnSoftKeyboardOpenCloseListener(new EmojiconsPopup.OnSoftKeyboardOpenCloseListener() {
+
+ @Override
+ public void onKeyboardOpen(int keyBoardHeight) {
+
+ }
+
+ @Override
+ public void onKeyboardClose() {
+ if (mEmojPopup.isShowing())
+ mEmojPopup.dismiss();
+ }
+ });
+
+ //On emoji clicked, add it to edittext
+ mEmojPopup.setOnEmojiconClickedListener(new EmojiconGridView.OnEmojiconClickedListener() {
+
+ @Override
+ public void onEmojiconClicked(Emojicon emojicon) {
+ if (mEditMessage == null || emojicon == null) {
+ return;
+ }
+
+ int start = mEditMessage.getSelectionStart();
+ int end = mEditMessage.getSelectionEnd();
+ if (start < 0) {
+ mEditMessage.append(emojicon.getEmoji());
+ } else {
+ mEditMessage.getText().replace(Math.min(start, end),
+ Math.max(start, end), emojicon.getEmoji(), 0,
+ emojicon.getEmoji().length());
+ }
+ }
+ });
+
+ //On backspace clicked, emulate the KEYCODE_DEL key event
+ mEmojPopup.setOnEmojiconBackspaceClickedListener(new EmojiconsPopup.OnEmojiconBackspaceClickedListener() {
+
+ @Override
+ public void onEmojiconBackspaceClicked(View v) {
+ KeyEvent event = new KeyEvent(
+ 0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
+ mEditMessage.dispatchKeyEvent(event);
+ }
+ });
+
+ // To toggle between text keyboard and emoji keyboard keyboard(Popup)
+ mEmojButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+
+ //If popup is not showing => emoji keyboard is not visible, we need to show it
+ if(!mEmojPopup.isShowing()){
+
+ //If keyboard is visible, simply show the emoji popup
+ if(mEmojPopup.isKeyBoardOpen()){
+ mEmojPopup.showAtBottom();
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard);
+ }
+
+ //else, open the text keyboard first and immediately after that show the emoji popup
+ else{
+ mEditMessage.setFocusableInTouchMode(true);
+ mEditMessage.requestFocus();
+ mEmojPopup.showAtBottomPending();
+ final InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.showSoftInput(mEditMessage, InputMethodManager.SHOW_IMPLICIT);
+ changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard);
+ }
+ }
+
+ //If popup is showing, simply dismiss it to show the undelying text keyboard
+ else{
+ mEmojPopup.dismiss();
+ }
+ }
+ });
+
+ // End of emojicon
+
mSendButton = (ImageButton) view.findViewById(R.id.textSendButton);
mSendButton.setOnClickListener(this.mSendButtonListener);
@@ -475,6 +593,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
registerForContextMenu(messagesView);
+ // Start of swipe refresh
+ // New Swipe refresh
+ swipeLayout = (SwipyRefreshLayout) view.findViewById(R.id.swipe_refresh_container);
+ swipeLayout.setOnRefreshListener(new ConversationSwipeRefreshListener(messageList, swipeLayout, this, messagesView, messageListAdapter));
+ // End of swipe refresh
+
return view;
}
@@ -594,7 +718,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
private void resendMessage(Message message) {
if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) {
- DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message);
+ DownloadableFile file = FileBackend.getFile(message);
if (!file.exists()) {
Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show();
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
@@ -614,7 +738,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
resId = R.string.file_url;
url = message.getFileParams().url.toString();
} else {
- url = message.getBody().trim();
+ url = message.getBody();
resId = R.string.file_url;
}
if (activity.copyTextToClipboard(url, resId)) {
@@ -645,7 +769,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
protected void highlightInConference(String nick) {
- String oldString = mEditMessage.getText().toString().trim();
+ String oldString = mEditMessage.getText().toString();
if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) {
mEditMessage.getText().insert(0, nick + ": ");
} else {
@@ -711,6 +835,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (size > 0) {
messagesView.setSelection(size - 1);
}
+ swipeLayout.setRefreshing(false);
}
private OnClickListener mUnblockClickListener = new OnClickListener() {
@@ -872,6 +997,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
case Presences.AWAY:
return R.drawable.ic_send_text_away;
case Presences.XA:
+ this.mSendButton
+ .setImageResource(R.drawable.ic_action_send_now_away);
+ break;
case Presences.DND:
return R.drawable.ic_send_text_dnd;
default:
@@ -963,11 +1091,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
if (conference && c.getNextCounterpart() != null) {
action = SendButtonAction.CANCEL;
} else {
- String setting = activity.getPreferences().getString("quick_action", "recent");
+ String setting = ConversationsPlusPreferences.quickAction();
if (!setting.equals("none") && UIHelper.receivedLocationQuestion(conversation.getLatestMessage())) {
setting = "location";
} else if (setting.equals("recent")) {
- setting = activity.getPreferences().getString("recently_used_quick_action", "text");
+ setting = ConversationsPlusPreferences.recentlyUsedQuickAction();
}
switch (setting) {
case "photo":
@@ -991,7 +1119,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
action = SendButtonAction.TEXT;
}
}
- if (activity.useSendButtonToIndicateStatus() && c != null
+ if (ConversationsPlusPreferences.sendButtonStatus() && c != null
&& c.getAccount().getStatus() == Account.State.ONLINE) {
if (c.getMode() == Conversation.MODE_SINGLE) {
status = c.getContact().getMostAvailableStatus();
@@ -1189,7 +1317,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
@Override
public boolean onEnterPressed() {
- if (activity.enterIsSend()) {
+ if (ConversationsPlusPreferences.enterIsSend()) {
sendMessage();
return true;
} else {
@@ -1290,4 +1418,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
}
+ private void changeEmojiKeyboardIcon(ImageView iconToBeChanged, int drawableResourceId){
+ iconToBeChanged.setImageResource(drawableResourceId);
+ }
+
}
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 5c783f54..f7d4564f 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -32,12 +32,14 @@ import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;
+import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener;
import java.util.Set;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
@@ -618,6 +620,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
this.mRegisterNew.setChecked(false);
}
if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) {
+ this.findViewById(R.id.editAccountBoxes).setVisibility(View.GONE);
+ this.findViewById(R.id.displayAccountFrame).setVisibility(View.VISIBLE);
+ TextView detailsAccountJid = (TextView)this.findViewById(R.id.detailsAccountJid);
+ if (this.mAccount.countPresences() > 0) {
+ detailsAccountJid.setText(this.mAccount.getJid().toBareJid().toString() + " (" + this.mAccount.countPresences() + ")");
+ detailsAccountJid.setOnClickListener(new ShowResourcesListDialogListener(EditAccountActivity.this, this.mAccount.getRoster().getContact(this.mAccount.getJid().toBareJid())));
+ } else {
+ detailsAccountJid.setText(this.mAccount.getJid().toBareJid().toString());
+ }
this.mStats.setVisibility(View.VISIBLE);
this.mBatteryOptimizations.setVisibility(showBatteryOptimizationWarning() ? View.VISIBLE : View.GONE);
this.mSessionEst.setText(UIHelper.readableTimeDifferenceFull(this, this.mAccount.getXmppConnection()
diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
index fc655b0c..4f273882 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
@@ -7,8 +7,9 @@ import android.view.KeyEvent;
import android.widget.EditText;
import eu.siacs.conversations.Config;
+import github.ankushsachdeva.emojicon.EmojiconEditText;
-public class EditMessage extends EditText {
+public class EditMessage extends EmojiconEditText {
public EditMessage(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
index f2511ecb..a6fb0fea 100644
--- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -15,6 +15,7 @@ import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
index a457bf96..9f8ac45c 100644
--- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java
@@ -15,6 +15,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
import com.soundcloud.android.crop.Crop;
import java.io.File;
@@ -23,6 +24,7 @@ import java.io.FileNotFoundException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.ExifHelper;
import eu.siacs.conversations.utils.FileUtils;
@@ -113,7 +115,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
if (avatarUri != null) {
publishButton.setText(R.string.publishing);
disablePublishButton();
- xmppConnectionService.publishAvatar(account, avatarUri,
+ AvatarService.getInstance().publishAvatar(account, avatarUri,
avatarPublication);
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index aa23e36d..05c9eea7 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -1,5 +1,20 @@
package eu.siacs.conversations.ui;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Locale;
+
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.tzur.conversations.Settings;
+import de.duenndns.ssl.MemorizingTrustManager;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.xmpp.XmppConnection;
+import github.ankushsachdeva.emojicon.EmojiconHandler;
+
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.content.DialogInterface;
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index 09bbe0df..d0cfe558 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -19,6 +19,11 @@ import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog;
+import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener;
+import de.thedevstack.conversationsplus.ui.listeners.ShareWithResizePictureUserDecisionListener;
+
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
@@ -234,34 +239,35 @@ public class ShareWithActivity extends XmppActivity {
return;
}
if (share.uris.size() != 0) {
- OnPresenceSelected callback = new OnPresenceSelected() {
- @Override
- public void onPresenceSelected() {
- if (share.image) {
- mToast = Toast.makeText(getApplicationContext(),
- getText(R.string.preparing_image),
- Toast.LENGTH_LONG);
- mToast.show();
- for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) {
- ShareWithActivity.this.xmppConnectionService
- .attachImageToConversation(conversation, i.next(),
- attachFileCallback);
- }
- } else {
- mToast = Toast.makeText(getApplicationContext(),
- getText(R.string.preparing_file),
- Toast.LENGTH_LONG);
- mToast.show();
- ShareWithActivity.this.xmppConnectionService
- .attachFileToConversation(conversation, share.uris.get(0),
- attachFileCallback);
- }
+ OnPresenceSelected callback;
+ if (this.share.image) {
+ callback = new OnPresenceSelected() {
+ @Override
+ public void onPresenceSelected() {
+ ResizePictureUserDecisionListener userDecisionListener = new ShareWithResizePictureUserDecisionListener(ShareWithActivity.this, conversation, xmppConnectionService, share.uris);
+ UserDecisionDialog userDecisionDialog = new UserDecisionDialog(ShareWithActivity.this, R.string.userdecision_question_resize_picture, userDecisionListener);
+ userDecisionDialog.decide(ConversationsPlusPreferences.resizePicture());
+ }
+ };
+ } else {
+ callback = new OnPresenceSelected() {
+ @Override
+ public void onPresenceSelected() {
+ mToast = Toast.makeText(getApplicationContext(),
+ getText(R.string.preparing_file),
+ Toast.LENGTH_LONG);
+ mToast.show();
+ ShareWithActivity.this.xmppConnectionService
+ .attachFileToConversation(conversation, share.uris.get(0),
+ attachFileCallback);
if (share.uuid == null) {
switchToConversation(conversation, null, true);
}
- finish();
- }
- };
+ finish();
+ }
+ };
+ }
+
if (conversation.getAccount().httpUploadAvailable()) {
callback.onPresenceSelected();
} else {
diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
index 355ee93c..c9638e18 100644
--- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -26,7 +26,6 @@ import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.text.Editable;
import android.text.TextWatcher;
-import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
@@ -55,6 +54,9 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -191,6 +193,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_conversation);
+ this.mHideOfflineContacts = ConversationsPlusPreferences.hideOffline();
mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
@@ -247,7 +250,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
}
});
- this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false);
}
@@ -538,12 +540,13 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
new IntentIntegrator(this).initiateScan();
return true;
case R.id.action_hide_offline:
- mHideOfflineContacts = !item.isChecked();
- getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit();
+ mHideOfflineContacts = !item.isChecked(); // the item is the menu item which is displayed, the inversion here calculates the new value
+ ConversationsPlusPreferences.commitHideOffline(mHideOfflineContacts);
if (mSearchEditText != null) {
filter(mSearchEditText.getText().toString());
}
- invalidateOptionsMenu();
+ invalidateOptionsMenu(); // Since the selection of this item changed the checked value, the options menu is now invalid
+ return true;
}
return super.onOptionsItemSelected(item);
}
@@ -657,12 +660,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
switch (intent.getAction()) {
case Intent.ACTION_SENDTO:
case Intent.ACTION_VIEW:
- Log.d(Config.LOGTAG, "received uri=" + intent.getData());
+ Logging.d(Config.LOGTAG, "received uri=" + intent.getData());
return new Invite(intent.getData()).invite();
case NfcAdapter.ACTION_NDEF_DISCOVERED:
for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
if (message instanceof NdefMessage) {
- Log.d(Config.LOGTAG, "received message=" + message);
+ Logging.d(Config.LOGTAG, "received message=" + message);
for (NdefRecord record : ((NdefMessage) message).getRecords()) {
switch (record.getTnf()) {
case NdefRecord.TNF_WELL_KNOWN:
@@ -694,7 +697,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
Contact contact = contacts.get(0);
if (invite.getFingerprint() != null) {
if (contact.addOtrFingerprint(invite.getFingerprint())) {
- Log.d(Config.LOGTAG,"added new fingerprint");
+ Logging.d(Config.LOGTAG,"added new fingerprint");
xmppConnectionService.syncRosterToDisk(contact.getAccount());
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 003b802c..3d3207e4 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -68,6 +68,10 @@ import java.util.Hashtable;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
@@ -358,18 +362,18 @@ public abstract class XmppActivity extends Activity {
super.onCreate(savedInstanceState);
metrics = getResources().getDisplayMetrics();
ExceptionHelper.init(getApplicationContext());
- mPrimaryTextColor = getResources().getColor(R.color.black87);
- mSecondaryTextColor = getResources().getColor(R.color.black54);
+ mPrimaryTextColor = getResources().getColor(R.color.primaryText);
+ mSecondaryTextColor = getResources().getColor(R.color.secondaryText);
mTertiaryTextColor = getResources().getColor(R.color.black12);
- mColorRed = getResources().getColor(R.color.red800);
+ mColorRed = getResources().getColor(R.color.warning);
mColorOrange = getResources().getColor(R.color.orange500);
- mColorGreen = getResources().getColor(R.color.green500);
+ mColorGreen = getResources().getColor(R.color.online);
mPrimaryColor = getResources().getColor(R.color.primary);
- mPrimaryBackgroundColor = getResources().getColor(R.color.grey50);
- mSecondaryBackgroundColor = getResources().getColor(R.color.grey200);
+ mPrimaryBackgroundColor = getResources().getColor(R.color.primaryBackground);
+ mSecondaryBackgroundColor = getResources().getColor(R.color.secondaryBackground);
this.mTheme = findTheme();
setTheme(this.mTheme);
- this.mUsingEnterKey = usingEnterKey();
+ this.mUsingEnterKey = ConversationsPlusPreferences.displayEnterKey();
mUseSubject = getPreferences().getBoolean("use_subject", true);
final ActionBar ab = getActionBar();
if (ab!=null) {
@@ -1007,7 +1011,7 @@ public abstract class XmppActivity extends Activity {
}
protected int findTheme() {
- if (getPreferences().getBoolean("use_larger_font", false)) {
+ if (ConversationsPlusPreferences.useLargerFont()) {
return R.style.ConversationsTheme_LargerText;
} else {
return R.style.ConversationsTheme;
@@ -1036,7 +1040,7 @@ public abstract class XmppActivity extends Activity {
}
protected Bitmap createQrCodeBitmap(String input, int size) {
- Log.d(Config.LOGTAG,"qr code requested size: "+size);
+ Logging.d(Config.LOGTAG,"qr code requested size: "+size);
try {
final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter();
final Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
@@ -1052,7 +1056,7 @@ public abstract class XmppActivity extends Activity {
}
}
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Log.d(Config.LOGTAG,"output size: "+width+"x"+height);
+ Logging.d(Config.LOGTAG,"output size: "+width+"x"+height);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (final WriterException e) {
@@ -1111,24 +1115,21 @@ public abstract class XmppActivity extends Activity {
}
}
- public AvatarService avatarService() {
- return xmppConnectionService.getAvatarService();
- }
-
class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
- private Message message = null;
+ private final boolean setSize;
+ private Message message = null;
- public BitmapWorkerTask(ImageView imageView) {
+ public BitmapWorkerTask(ImageView imageView, boolean setSize) {
imageViewReference = new WeakReference<>(imageView);
+ this.setSize = setSize;
}
@Override
protected Bitmap doInBackground(Message... params) {
message = params[0];
try {
- return xmppConnectionService.getFileBackend().getThumbnail(
- message, (int) (metrics.density * 288), false);
+ return ImageUtil.getThumbnail(message, (int) (metrics.density * 288), false);
} catch (FileNotFoundException e) {
return null;
}
@@ -1141,26 +1142,35 @@ public abstract class XmppActivity extends Activity {
if (imageView != null) {
imageView.setImageBitmap(bitmap);
imageView.setBackgroundColor(0x00000000);
+ if (setSize) {
+ imageView.setLayoutParams(new LinearLayout.LayoutParams(
+ bitmap.getWidth(), bitmap.getHeight()));
+ }
}
}
}
}
- public void loadBitmap(Message message, ImageView imageView) {
+ public void loadBitmap(Message message, ImageView imageView, boolean setSize) {
Bitmap bm;
try {
- bm = xmppConnectionService.getFileBackend().getThumbnail(message,
- (int) (metrics.density * 288), true);
+ bm = ImageUtil.getThumbnail(message,(int) (metrics.density * 288), true);
} catch (FileNotFoundException e) {
bm = null;
}
+
if (bm != null) {
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
+ if (setSize) {
+ imageView.setLayoutParams(new LinearLayout.LayoutParams(
+ bm.getWidth(), bm.getHeight()));
+ }
} else {
if (cancelPotentialWork(message, imageView)) {
imageView.setBackgroundColor(0xff333333);
- final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+
+ final BitmapWorkerTask task = new BitmapWorkerTask(imageView, setSize);
final AsyncDrawable asyncDrawable = new AsyncDrawable(
getResources(), null, task);
imageView.setImageDrawable(asyncDrawable);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
index 98250af9..24b58af4 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java
@@ -1,5 +1,13 @@
package eu.siacs.conversations.ui.adapter;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.services.AvatarService;
+import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.ui.ManageAccountActivity;
+
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -43,7 +51,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
}
TextView statusView = (TextView) view.findViewById(R.id.account_status);
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
- imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
+ imageView.setImageBitmap(AvatarService.getInstance().get(account, activity.getPixel(48)));
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index f5f48a26..b4069fd1 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -19,13 +19,35 @@ import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener;
+import de.tzur.conversations.Settings;
+
+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.entities.Message;
import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.utils.UIHelper;
+import github.ankushsachdeva.emojicon.EmojiconTextView;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
public class ConversationAdapter extends ArrayAdapter<Conversation> {
@@ -44,11 +66,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
view = inflater.inflate(R.layout.conversation_list_row,parent, false);
}
Conversation conversation = getItem(position);
+ // Highlight the currently selected conversation
if (this.activity instanceof ConversationActivity) {
- View swipeableItem = view.findViewById(R.id.swipeable_item);
ConversationActivity a = (ConversationActivity) this.activity;
- int c = a.highlightSelectedConversations() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor();
- swipeableItem.setBackgroundColor(c);
+ int c = conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor();
+ view.findViewById(R.id.conversationListRowContent).setBackgroundColor(c);
+ view.findViewById(R.id.conversationListRowFrame).setBackgroundColor(c);
}
TextView convName = (TextView) view.findViewById(R.id.conversation_name);
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
@@ -61,6 +84,30 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage);
ImageView notificationStatus = (ImageView) view.findViewById(R.id.notification_status);
+ if (Settings.SHOW_ONLINE_STATUS && conversation.getAccount().getStatus() == Account.State.ONLINE) {
+ TextView status = (TextView) view.findViewById(R.id.status);
+
+ String color = "#000000";
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ switch (conversation.getContact().getMostAvailableStatus()) {
+ case Presences.ONLINE:
+ case Presences.CHAT:
+ color = "#259B23";
+ break;
+ case Presences.AWAY:
+ case Presences.XA:
+ color = "#FF9800";
+ break;
+ case Presences.DND:
+ color = "#E51C23";
+ break;
+ }
+ } else if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().online()) {
+ color = "#259B23";
+ }
+ status.setBackgroundColor(Color.parseColor(color));
+ }
+
Message message = conversation.getLatestMessage();
if (!conversation.isRead()) {
@@ -74,7 +121,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|| message.getTransferable().getStatus() != Transferable.STATUS_DELETED)) {
mLastMessage.setVisibility(View.GONE);
imagePreview.setVisibility(View.VISIBLE);
- activity.loadBitmap(message, imagePreview);
+ activity.loadBitmap(message, imagePreview, false);
} else {
Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message);
mLastMessage.setVisibility(View.VISIBLE);
@@ -111,7 +158,8 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
mTimestamp.setText(UIHelper.readableTimeDifference(activity,conversation.getLatestMessage().getTimeSent()));
ImageView profilePicture = (ImageView) view.findViewById(R.id.conversation_image);
- loadAvatar(conversation,profilePicture);
+ profilePicture.setOnLongClickListener(new ShowResourcesListDialogListener(activity, conversation.getContact()));
+ loadAvatar(conversation, profilePicture);
return view;
}
@@ -126,7 +174,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
@Override
protected Bitmap doInBackground(Conversation... params) {
- return activity.avatarService().get(params[0], activity.getPixel(56));
+ return AvatarService.getInstance().get(params[0], activity.getPixel(56));
}
@Override
@@ -143,7 +191,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
public void loadAvatar(Conversation conversation, ImageView imageView) {
if (cancelPotentialWork(conversation, imageView)) {
- final Bitmap bm = activity.avatarService().get(conversation, activity.getPixel(56), true);
+ final Bitmap bm = AvatarService.getInstance().get(conversation, activity.getPixel(56), true);
if (bm != null) {
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
index 47414f90..90d5a382 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -1,5 +1,20 @@
package eu.siacs.conversations.ui.adapter;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+
+import de.tzur.conversations.Settings;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.services.AvatarService;
+import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -16,16 +31,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.entities.ListItem;
-import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jid.Jid;
-
public class ListItemAdapter extends ArrayAdapter<ListItem> {
protected XmppActivity activity;
@@ -45,8 +50,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
public ListItemAdapter(XmppActivity activity, List<ListItem> objects) {
super(activity, 0, objects);
this.activity = activity;
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
- this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
+ this.showDynamicTags = ConversationsPlusPreferences.showDynamicTags();
}
@Override
@@ -57,6 +61,12 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
if (view == null) {
view = inflater.inflate(R.layout.contact, parent, false);
}
+
+ if (Settings.SHOW_ONLINE_STATUS) {
+ TextView tvStatus = (TextView) view.findViewById(R.id.contact_status);
+ tvStatus.setBackgroundColor(item.getStatusColor());
+ }
+
TextView tvName = (TextView) view.findViewById(R.id.contact_display_name);
TextView tvJid = (TextView) view.findViewById(R.id.contact_jid);
ImageView picture = (ImageView) view.findViewById(R.id.contact_photo);
@@ -106,7 +116,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
@Override
protected Bitmap doInBackground(ListItem... params) {
- return activity.avatarService().get(params[0], activity.getPixel(48));
+ return AvatarService.getInstance().get(params[0], activity.getPixel(48));
}
@Override
@@ -123,7 +133,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
public void loadAvatar(ListItem item, ImageView imageView) {
if (cancelPotentialWork(item, imageView)) {
- final Bitmap bm = activity.avatarService().get(item,activity.getPixel(48),true);
+ final Bitmap bm = AvatarService.getInstance().get(item,activity.getPixel(48),true);
if (bm != null) {
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index a9234e1a..ed2a23d2 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -11,6 +11,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
@@ -35,24 +36,33 @@ import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.regex.Matcher;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Message.FileParams;
import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.services.AvatarService;
+import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.UIHelper;
+import github.ankushsachdeva.emojicon.EmojiconTextView;
+
public class MessageAdapter extends ArrayAdapter<Message> {
private static final int SENT = 0;
private static final int RECEIVED = 1;
private static final int STATUS = 2;
+ private static final int NULL = 3;
private ConversationActivity activity;
@@ -152,12 +162,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
info = getContext().getString(R.string.offering);
break;
case Message.STATUS_SEND_RECEIVED:
- if (mIndicateReceived) {
+ if (ConversationsPlusPreferences.indicateReceived()) {
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
}
break;
case Message.STATUS_SEND_DISPLAYED:
- if (mIndicateReceived) {
+ if (ConversationsPlusPreferences.indicateReceived()) {
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
}
break;
@@ -404,7 +414,8 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE);
FileParams params = message.getFileParams();
- double target = metrics.density * 288;
+ //TODO: Check what value add the following lines have (compared with setting height/width in XmppActivity.loadBitmap from thumbnail after thumbnail is created)
+ /*double target = metrics.density * 288;
int scalledW;
int scalledH;
if (params.width <= params.height) {
@@ -416,8 +427,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scalledW, scalledH);
layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4));
- viewHolder.image.setLayoutParams(layoutParams);
- activity.loadBitmap(message, viewHolder.image);
+ viewHolder.image.setLayoutParams(layoutParams);*/
+ //TODO Why should this be calculated by hand???
+ activity.loadBitmap(message, viewHolder.image, true);
viewHolder.image.setOnClickListener(new OnClickListener() {
@Override
@@ -501,8 +513,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (type == STATUS) {
if (conversation.getMode() == Conversation.MODE_SINGLE) {
- viewHolder.contact_picture.setImageBitmap(activity
- .avatarService().get(conversation.getContact(),
+ viewHolder.contact_picture.setImageBitmap(AvatarService.getInstance().get(conversation.getContact(),
activity.getPixel(32)));
viewHolder.contact_picture.setAlpha(0.5f);
viewHolder.status_message.setText(message.getBody());
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
new file mode 100644
index 00000000..a5c5e2aa
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java
@@ -0,0 +1,152 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.view.View;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout;
+
+import java.util.List;
+
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener updates the UI when messages are loaded from the server.
+ */
+public class ConversationMoreMessagesLoadedListener implements XmppConnectionService.OnMoreMessagesLoaded {
+ private SwipyRefreshLayout swipeLayout;
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ListView messagesView;
+ private MessageAdapter messageListAdapter;
+ private Toast messageLoaderToast;
+ /*
+ The current loading status
+ */
+ private boolean loadingMessages = false;
+ /**
+ * Whether the user is loading only history messages or not.
+ * History messages are messages which are older than the oldest in the database.
+ */
+ private boolean loadHistory = true;
+
+ public ConversationMoreMessagesLoadedListener(SwipyRefreshLayout swipeLayout, List<Message> messageList, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.swipeLayout = swipeLayout;
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.messagesView = messagesView;
+ this.messageListAdapter = messageListAdapter;
+ }
+
+ public void setLoadHistory(boolean value) {
+ this.loadHistory = value;
+ }
+
+ public void setLoadingInProgress() {
+ this.loadingMessages = true;
+ }
+
+ public boolean isLoadingInProgress() {
+ return this.loadingMessages;
+ }
+
+ @Override
+ public void onMoreMessagesLoaded(final int c, final Conversation conversation) {
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ // Current selected conversation is not the same the messages are loaded - skip updating message view and hide loading graphic
+ if (activity.getSelectedConversation() != conversation) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ return;
+ }
+ // No new messages are loaded
+ if (0 == c) {
+ if (this.loadHistory) {
+ conversation.setHasMessagesLeftOnServer(false);
+ }
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final int oldPosition = messagesView.getFirstVisiblePosition(); // Always 0 - because loading starts always when hitting the top
+ String uuid = null;
+ boolean oldMessageListWasEmpty = messageList.isEmpty();
+ if (-1 < oldPosition && messageList.size() > oldPosition) {
+ Message message = messageList.get(oldPosition);
+ uuid = message != null ? message.getUuid() : null;
+ }
+ View v = messagesView.getChildAt(0);
+ final int pxOffset = (v == null) ? 0 : v.getTop();
+
+ conversation.populateWithMessages(messageList); // This overrides the old message list
+ fragment.updateStatusMessages(); // This adds "messages" to the list for the status
+ messageListAdapter.notifyDataSetChanged();
+ loadingMessages = false; // Loading of messages is finished - next query can be loaded
+
+ int pos = getIndexOf(uuid, messageList);
+
+ if (!oldMessageListWasEmpty) {
+ messagesView.setSelectionFromTop(pos, pxOffset);
+ }
+
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ swipeLayout.setRefreshing(false);
+ }
+ });
+ }
+
+ @Override
+ public void informUser(final int resId) {
+ final ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (messageLoaderToast != null) {
+ messageLoaderToast.cancel();
+ }
+ messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG);
+ messageLoaderToast.show();
+ }
+ });
+
+ }
+
+ private int getIndexOf(String uuid, List<Message> messages) {
+ if (uuid == null) {
+ return 0;
+ }
+ for (int i = 0; i < messages.size(); ++i) {
+ if (uuid.equals(messages.get(i).getUuid())) {
+ return i;
+ } else {
+ Message next = messages.get(i);
+ while(next != null && next.wasMergedIntoPrevious()) {
+ if (uuid.equals(next.getUuid())) {
+ return i;
+ }
+ next = next.next();
+ }
+
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
new file mode 100644
index 00000000..e698c9b2
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java
@@ -0,0 +1,93 @@
+package eu.siacs.conversations.ui.listeners;
+
+import android.widget.ListView;
+
+import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout;
+import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection;
+
+import java.util.List;
+
+import de.thedevstack.android.logcat.Logging;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.MessageArchiveService;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.ui.ConversationFragment;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+
+/**
+ * This listener starts loading messages from the server.
+ */
+public class ConversationSwipeRefreshListener implements SwipyRefreshLayout.OnRefreshListener {
+ private List<Message> messageList;
+ private ConversationFragment fragment;
+ private ConversationMoreMessagesLoadedListener listener;
+
+ public ConversationSwipeRefreshListener(List<Message> messageList, SwipyRefreshLayout swipeLayout, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) {
+ this.messageList = messageList;
+ this.fragment = fragment;
+ this.listener = new ConversationMoreMessagesLoadedListener(swipeLayout, messageList, fragment, messagesView, messageListAdapter);
+ }
+
+ @Override
+ public void onRefresh(SwipyRefreshLayoutDirection direction) {
+ Logging.d(Config.LOGTAG, "Refresh swipe container");
+ Logging.d(Config.LOGTAG, "Refresh direction " + direction);
+ synchronized (this.messageList) {
+ long timestamp;
+ if (SwipyRefreshLayoutDirection.TOP == direction) { // Load history -> messages sent/received before first message in database
+ if (messageList.isEmpty()) {
+ timestamp = System.currentTimeMillis();
+ } else {
+ timestamp = this.messageList.get(0).getTimeSent(); // works only because of the ordering (last msg = first msg in list)
+ }
+ ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ this.listener.setLoadHistory(true);
+ activity.xmppConnectionService.loadMoreMessages(activity.getSelectedConversation(), timestamp, this.listener);
+ } else if (SwipyRefreshLayoutDirection.BOTTOM == direction) { // load messages sent/received between last received or last session establishment and now
+ Logging.d("mam", "loading missing messages from mam (last session establishing or last received message)");
+ final ConversationActivity activity = (ConversationActivity) fragment.getActivity();
+ long lastSessionEstablished = this.getTimestampOfLastSessionEstablished(activity.getSelectedConversation());
+ long lastReceivedMessage = this.getTimestampOfLastReceivedOrTransmittedMessage();
+ long startTimestamp = Math.min(lastSessionEstablished, lastReceivedMessage);
+ MessageArchiveService.Query query = activity.xmppConnectionService.getMessageArchiveService().query(activity.getSelectedConversation(), startTimestamp, System.currentTimeMillis());
+ if (query != null) {
+ this.listener.setLoadHistory(false);
+ query.setCallback(this.listener);
+ } else {
+ Logging.d("mam", "no query built - no messages loaded");
+ this.listener.onMoreMessagesLoaded(0, activity.getSelectedConversation());
+ this.listener.informUser(R.string.no_more_history_on_server);
+ }
+ this.listener.informUser(R.string.fetching_history_from_server);
+ }
+ }
+ Logging.d(Config.LOGTAG, "End Refresh swipe container");
+ }
+
+ private long getTimestampOfLastReceivedOrTransmittedMessage() {
+ long lastReceivedOrTransmittedMessage = Long.MAX_VALUE;
+ if (null != this.messageList
+ && !this.messageList.isEmpty()) {
+ int lastMessageIndex = this.messageList.size() - 1;
+ if (0 <= lastMessageIndex && this.messageList.size() > lastMessageIndex) {
+ lastReceivedOrTransmittedMessage = this.messageList.get(lastMessageIndex).getTimeSent();
+ }
+ }
+
+ return lastReceivedOrTransmittedMessage;
+ }
+
+ private long getTimestampOfLastSessionEstablished(Conversation conversation) {
+ long lastSessionEstablished = Long.MAX_VALUE;
+ if (null != conversation
+ && null != conversation.getAccount()
+ && null != conversation.getAccount().getXmppConnection()) {
+ lastSessionEstablished = conversation.getAccount().getXmppConnection().getLastSessionEstablished();
+ }
+ return lastSessionEstablished;
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index 1ef5fb3f..4850f19d 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -12,6 +12,7 @@ import java.security.MessageDigest;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.security.SecureRandom;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
index 306d50c2..58d53216 100644
--- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
@@ -28,11 +28,22 @@ import de.measite.minidns.DNSMessage;
import de.measite.minidns.Record;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
+import de.measite.minidns.Record.CLASS;
+import de.measite.minidns.record.SRV;
import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.SRV;
import de.measite.minidns.util.NameUtil;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.dto.SrvRecord;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.jid.Jid;
diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
index 8799b4a5..892d5a00 100644
--- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
@@ -18,6 +18,9 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@@ -28,6 +31,17 @@ import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.DialogInterface.OnClickListener;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.preference.PreferenceManager;
+import android.text.format.DateUtils;
+
public class ExceptionHelper {
public static void init(Context context) {
if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
@@ -38,9 +52,7 @@ public class ExceptionHelper {
public static boolean checkForCrash(ConversationActivity activity, final XmppConnectionService service) {
try {
- final SharedPreferences preferences = PreferenceManager
- .getDefaultSharedPreferences(activity);
- boolean neverSend = preferences.getBoolean("never_send", false);
+ boolean neverSend = ConversationsPlusPreferences.neverSend();
if (neverSend) {
return false;
}
@@ -89,7 +101,7 @@ public class ExceptionHelper {
@Override
public void onClick(DialogInterface dialog, int which) {
- Log.d(Config.LOGTAG, "using account="
+ Logging.d(Config.LOGTAG, "using account="
+ finalAccount.getJid().toBareJid()
+ " to send in stack trace");
Conversation conversation = null;
@@ -108,8 +120,7 @@ public class ExceptionHelper {
@Override
public void onClick(DialogInterface dialog, int which) {
- preferences.edit().putBoolean("never_send", true)
- .apply();
+ ConversationsPlusPreferences.applyNeverSend(true);
}
});
builder.create().show();
diff --git a/src/main/java/eu/siacs/conversations/utils/ExifHelper.java b/src/main/java/eu/siacs/conversations/utils/ExifHelper.java
index ceda7293..eac2d0f0 100644
--- a/src/main/java/eu/siacs/conversations/utils/ExifHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/ExifHelper.java
@@ -16,7 +16,7 @@
package eu.siacs.conversations.utils;
-import android.util.Log;
+import de.thedevstack.android.logcat.Logging;
import java.io.IOException;
import java.io.InputStream;
@@ -56,7 +56,7 @@ public class ExifHelper {
}
length = pack(buf, 0, 2, false);
if (length < 2) {
- Log.e(TAG, "Invalid length");
+ Logging.e(TAG, "Invalid length");
return 0;
}
length -= 2;
@@ -91,7 +91,7 @@ public class ExifHelper {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
- Log.e(TAG, "Invalid byte order");
+ Logging.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);
@@ -99,7 +99,7 @@ public class ExifHelper {
// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
- Log.e(TAG, "Invalid offset");
+ Logging.e(TAG, "Invalid offset");
return 0;
}
offset += count;
@@ -123,7 +123,7 @@ public class ExifHelper {
case 8:
return 270;
}
- Log.i(TAG, "Unsupported orientation");
+ Logging.i(TAG, "Unsupported orientation");
return 0;
}
offset += 12;
@@ -131,7 +131,7 @@ public class ExifHelper {
}
}
- Log.i(TAG, "Orientation not found");
+ Logging.i(TAG, "Orientation not found");
return 0;
}
diff --git a/src/main/java/eu/siacs/conversations/utils/PRNGFixes.java b/src/main/java/eu/siacs/conversations/utils/PRNGFixes.java
index 8fe67234..5faa1fa7 100644
--- a/src/main/java/eu/siacs/conversations/utils/PRNGFixes.java
+++ b/src/main/java/eu/siacs/conversations/utils/PRNGFixes.java
@@ -2,7 +2,6 @@ package eu.siacs.conversations.utils;
import android.os.Build;
import android.os.Process;
-import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -19,6 +18,8 @@ import java.security.SecureRandom;
import java.security.SecureRandomSpi;
import java.security.Security;
+import de.thedevstack.android.logcat.Logging;
+
/**
* Fixes for the output of the default PRNG having low entropy.
*
@@ -209,7 +210,7 @@ public final class PRNGFixes {
} catch (IOException e) {
// On a small fraction of devices /dev/urandom is not writable.
// Log and ignore.
- Log.w(PRNGFixes.class.getSimpleName(),
+ Logging.w(PRNGFixes.class.getSimpleName(),
"Failed to mix seed into " + URANDOM_FILE);
} finally {
mSeeded = true;
diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
index 6c1b4bef..774532d1 100644
--- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java
@@ -1,5 +1,9 @@
package eu.siacs.conversations.utils;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
import android.Manifest;
import android.content.Context;
import android.content.CursorLoader;
@@ -8,13 +12,11 @@ import android.content.Loader.OnLoadCompleteListener;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Profile;
-import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
public class PhoneHelper {
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index cf1e0d3b..e1b1a2a9 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -5,19 +5,39 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.Pair;
+import java.math.BigDecimal;
+import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.net.URLConnection;
import java.util.Calendar;
import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.xmpp.jid.Jid;
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.text.Spannable.Factory;
+import android.text.style.ImageSpan;
+import android.text.Spannable;
+import android.util.Pair;
+
public class UIHelper {
private static String BLACK_HEART_SUIT = "\u2665";
@@ -190,7 +210,7 @@ public class UIHelper {
return new Pair<>(context.getString(R.string.location), true);
}
} else{
- return new Pair<>(message.getBody().trim(), false);
+ return new Pair<>(message.getBody(), false);
}
}
}
@@ -241,13 +261,27 @@ public class UIHelper {
}
}
+ public static String getStatusColor(int status) {
+ switch (status) {
+ case Presences.ONLINE:
+ case Presences.CHAT:
+ return "#259B23";
+ case Presences.AWAY:
+ case Presences.XA:
+ return "#FF9800";
+ case Presences.DND:
+ return "#E51C23";
+ }
+ return "#CCCCCC";
+ }
+
private static String getDisplayedMucCounterpart(final Jid counterpart) {
if (counterpart==null) {
return "";
} else if (!counterpart.isBareJid()) {
- return counterpart.getResourcepart().trim();
+ return counterpart.getResourcepart();
} else {
- return counterpart.toString().trim();
+ return counterpart.toString();
}
}
@@ -257,8 +291,24 @@ public class UIHelper {
|| message.getType() != Message.TYPE_TEXT) {
return false;
}
- String body = message.getBody() == null ? null : message.getBody().trim().toLowerCase(Locale.getDefault());
+ String body = message.getBody() == null ? null : message.getBody().toLowerCase(Locale.getDefault());
body = body.replace("?","").replace("¿","");
return LOCATION_QUESTIONS.contains(body);
}
+
+ public static String getHumanReadableFileSize(long filesize) {
+ if (0 > filesize) {
+ return "?";
+ }
+ double size = Double.valueOf(filesize);
+ String[] sizes = {" bytes", " Kb", " Mb", " Gb", " Tb"};
+ int i = 0;
+ while (1023 < size) {
+ size /= 1024d;
+ ++i;
+ }
+ BigDecimal readableSize = new BigDecimal(size);
+ readableSize = readableSize.setScale(2, BigDecimal.ROUND_HALF_UP);
+ return readableSize.doubleValue() + sizes[i];
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java
index 34794be1..90eb112d 100644
--- a/src/main/java/eu/siacs/conversations/xml/Element.java
+++ b/src/main/java/eu/siacs/conversations/xml/Element.java
@@ -1,11 +1,11 @@
package eu.siacs.conversations.xml;
-import android.util.Log;
-
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.utils.XmlHelper;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@@ -128,7 +128,7 @@ public class Element {
try {
return Jid.fromString(jid);
} catch (final InvalidJidException e) {
- Log.e(Config.LOGTAG, "could not parse jid " + jid);
+ Logging.e(Config.LOGTAG, "could not parse jid " + jid);
return null;
}
}
diff --git a/src/main/java/eu/siacs/conversations/xml/XmlReader.java b/src/main/java/eu/siacs/conversations/xml/XmlReader.java
index aeaaa593..a58dc43f 100644
--- a/src/main/java/eu/siacs/conversations/xml/XmlReader.java
+++ b/src/main/java/eu/siacs/conversations/xml/XmlReader.java
@@ -12,6 +12,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import de.thedevstack.android.logcat.Logging;
+
import eu.siacs.conversations.Config;
public class XmlReader {
@@ -25,7 +30,7 @@ public class XmlReader {
this.parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
true);
} catch (XmlPullParserException e) {
- Log.d(Config.LOGTAG, "error setting namespace feature on parser");
+ Logging.d(Config.LOGTAG, "error setting namespace feature on parser");
}
this.wakeLock = wakeLock;
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index 37b2da68..ab647a15 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.xmpp;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
@@ -13,6 +14,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParserException;
@@ -20,6 +22,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.math.BigInteger;
import java.net.ConnectException;
import java.net.IDN;
@@ -34,11 +37,16 @@ import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.TreeSet;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
@@ -48,6 +56,9 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.dto.SrvRecord;
+
import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.XmppDomainVerifier;
@@ -88,7 +99,7 @@ import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
public class XmppConnection implements Runnable {
-
+ private static final int DEFAULT_PORT = 5222;
private static final int PACKET_IQ = 0;
private static final int PACKET_MESSAGE = 1;
private static final int PACKET_PRESENCE = 2;
@@ -220,7 +231,7 @@ public class XmppConnection implements Runnable {
}
protected void connect() {
- Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": connecting");
features.encryptionEnabled = false;
lastConnect = SystemClock.elapsedRealtime();
lastPingSent = SystemClock.elapsedRealtime();
@@ -265,7 +276,7 @@ public class XmppConnection implements Runnable {
} else if (DNSHelper.isIp(account.getServer().toString())) {
socket = new Socket();
try {
- socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
+ socket.connect(new InetSocketAddress(account.getServer().toString(), DEFAULT_PORT), Config.SOCKET_TIMEOUT * 1000);
} catch (IOException e) {
throw new UnknownHostException();
}
@@ -347,7 +358,7 @@ public class XmppConnection implements Runnable {
} catch (final SocksSocketFactory.SocksProxyNotFoundException e) {
this.changeStatus(Account.State.TOR_NOT_AVAILABLE);
} catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
this.changeStatus(Account.State.OFFLINE);
this.attempt--; //don't count attempt when reconnecting instantly anyway
} finally {
@@ -659,7 +670,7 @@ public class XmppConnection implements Runnable {
callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
- Log.e(Config.LOGTAG, account.getJid().toBareJid().toString() + ": ignoring spoofed iq packet");
+ Logging.e(Config.LOGTAG, account.getJid().toBareJid().toString() + ": ignoring spoofed iq packet");
}
}
} else if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) {
@@ -766,16 +777,16 @@ public class XmppConnection implements Runnable {
try {
if (keys.has(Account.PINNED_MECHANISM_KEY) &&
keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority()) {
- Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() +
+ Logging.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() +
" has lower priority (" + String.valueOf(saslMechanism.getPriority()) +
") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) +
"). Possible downgrade attack?");
throw new SecurityException();
}
} catch (final JSONException e) {
- Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
+ Logging.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
}
- Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism());
+ Logging.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism());
auth.setAttribute("mechanism", saslMechanism.getMechanism());
if (!saslMechanism.getClientFirstMessage().isEmpty()) {
auth.setContent(saslMechanism.getClientFirstMessage());
@@ -786,7 +797,7 @@ public class XmppConnection implements Runnable {
}
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) {
if (Config.EXTENDED_SM_LOGGING) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived);
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived);
}
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion);
this.tagWriter.writeStanzaAsync(resume);
@@ -858,7 +869,7 @@ public class XmppConnection implements Runnable {
URL uri = new URL(urlString);
captcha = BitmapFactory.decodeStream(uri.openConnection().getInputStream());
} catch (IOException e) {
- Log.e(Config.LOGTAG, e.toString());
+ Logging.e(Config.LOGTAG, e.toString());
}
}
@@ -927,11 +938,11 @@ public class XmppConnection implements Runnable {
sendPostBindInitialization();
}
} else {
- Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure");
+ Logging.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure");
disconnect(true);
}
} else {
- Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure");
+ Logging.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure");
disconnect(true);
}
}
@@ -991,7 +1002,7 @@ public class XmppConnection implements Runnable {
if (packet.getType() == IqPacket.TYPE.RESULT) {
sendPostBindInitialization();
} else if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not init sessions");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not init sessions");
disconnect(true);
}
}
@@ -1080,13 +1091,13 @@ public class XmppConnection implements Runnable {
enableAdvancedStreamFeatures();
}
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not query disco info for " + jid.toString());
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not query disco info for " + jid.toString());
}
if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
mPendingServiceDiscoveries--;
if (mPendingServiceDiscoveries == 0) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": done with service discovery");
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": done with service discovery");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
changeStatus(Account.State.ONLINE);
if (bindListener != null) {
bindListener.onBind(account);
@@ -1146,11 +1157,11 @@ public class XmppConnection implements Runnable {
@Override
public void onIqPacketReceived(final Account account, final IqPacket packet) {
if (!packet.hasChild("error")) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": successfully enabled carbons");
features.carbonsEnabled = true;
} else {
- Log.d(Config.LOGTAG, account.getJid().toBareJid()
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ ": error enableing carbons " + packet.toString());
}
}
@@ -1163,11 +1174,11 @@ public class XmppConnection implements Runnable {
if (streamError != null && streamError.hasChild("conflict")) {
final String resource = account.getResource().split("\\.")[0];
account.setResource(resource + "." + nextRandomId());
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
account.getJid().toBareJid() + ": switching resource due to conflict ("
+ account.getResource() + ")");
} else if (streamError != null) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": stream error "+streamError.toString());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": stream error "+streamError.toString());
}
}
@@ -1281,12 +1292,12 @@ public class XmppConnection implements Runnable {
}
public void disconnect(final boolean force) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
if (force) {
try {
socket.close();
} catch(Exception e) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": exception during force close ("+e.getMessage()+")");
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": exception during force close ("+e.getMessage()+")");
}
return;
} else {
@@ -1379,7 +1390,12 @@ public class XmppConnection implements Runnable {
}
public long getLastSessionEstablished() {
- final long diff = SystemClock.elapsedRealtime() - this.lastSessionStarted;
+ final long diff;
+ if (this.lastSessionStarted == 0) {
+ diff = SystemClock.elapsedRealtime() - this.lastConnect;
+ } else {
+ diff = SystemClock.elapsedRealtime() - this.lastSessionStarted;
+ }
return System.currentTimeMillis() - diff;
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 56582f97..11bfdd8d 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -16,13 +16,23 @@ import java.util.Locale;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.SystemClock;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.OnMessageCreatedCallback;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.DownloadableFile;
+import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
@@ -97,7 +107,7 @@ public class JingleConnection implements Transferable {
public void onFileTransmitted(DownloadableFile file) {
if (responder.equals(account.getJid())) {
sendSuccess();
- mXmppConnectionService.getFileBackend().updateFileParams(message);
+ MessageUtil.updateFileParams(message);
mXmppConnectionService.databaseBackend.createMessage(message);
mXmppConnectionService.markMessage(message,Message.STATUS_RECEIVED);
if (acceptedAutomatically) {
@@ -109,7 +119,7 @@ public class JingleConnection implements Transferable {
file.delete();
}
}
- Log.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+file.getSha1Sum()+")");
+ Logging.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+file.getSha1Sum()+")");
if (message.getEncryption() != Message.ENCRYPTION_PGP) {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(file));
@@ -139,17 +149,17 @@ public class JingleConnection implements Transferable {
@Override
public void success() {
if (initiator.equals(account.getJid())) {
- Log.d(Config.LOGTAG, "we were initiating. sending file");
+ Logging.d(Config.LOGTAG, "we were initiating. sending file");
transport.send(file, onFileTransmissionSatusChanged);
} else {
transport.receive(file, onFileTransmissionSatusChanged);
- Log.d(Config.LOGTAG, "we were responding. receiving file");
+ Logging.d(Config.LOGTAG, "we were responding. receiving file");
}
}
@Override
public void failed() {
- Log.d(Config.LOGTAG, "proxy activation failed");
+ Logging.d(Config.LOGTAG, "proxy activation failed");
}
};
@@ -195,13 +205,13 @@ public class JingleConnection implements Transferable {
returnResult = this.receiveFallbackToIbb(packet);
} else {
returnResult = false;
- Log.d(Config.LOGTAG, "trying to fallback to something unknown"
+ Logging.d(Config.LOGTAG, "trying to fallback to something unknown"
+ packet.toString());
}
} else if (packet.isAction("transport-accept")) {
returnResult = this.receiveTransportAccept(packet);
} else {
- Log.d(Config.LOGTAG, "packet arrived in connection. action was "
+ Logging.d(Config.LOGTAG, "packet arrived in connection. action was "
+ packet.getAction());
returnResult = false;
}
@@ -263,14 +273,14 @@ public class JingleConnection implements Transferable {
@Override
public void failed() {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"connection to our own primary candidete failed");
sendInitRequest();
}
@Override
public void established() {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"succesfully connected to our own primary candidate");
mergeCandidate(candidate);
sendInitRequest();
@@ -278,7 +288,8 @@ public class JingleConnection implements Transferable {
});
mergeCandidate(candidate);
} else {
- Log.d(Config.LOGTAG, "no primary candidate of our own was found");
+ Logging.d(Config.LOGTAG,
+ "no primary candidate of our own was found");
sendInitRequest();
}
}
@@ -363,20 +374,19 @@ public class JingleConnection implements Transferable {
mXmppConnectionService.updateConversationUi();
if (mJingleConnectionManager.hasStoragePermission()
&& size < this.mJingleConnectionManager.getAutoAcceptFileSize()) {
- Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom());
+ Logging.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom());
this.acceptedAutomatically = true;
this.sendAccept();
} else {
message.markUnread();
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"not auto accepting new file offer with size: "
+ size
+ " allowed size:"
- + this.mJingleConnectionManager
- .getAutoAcceptFileSize());
+ + ConversationsPlusPreferences.autoAcceptFileSize());
this.mXmppConnectionService.getNotificationService().push(message);
}
- this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false);
+ this.file = FileBackend.getFile(message, false);
if (mXmppAxolotlMessage != null) {
XmppAxolotlMessage.XmppAxolotlKeyTransportMessage transportMessage = account.getAxolotlService().processReceivingKeyTransportMessage(mXmppAxolotlMessage);
if (transportMessage != null) {
@@ -385,7 +395,7 @@ public class JingleConnection implements Transferable {
this.file.setIv(transportMessage.getIv());
message.setAxolotlFingerprint(transportMessage.getFingerprint());
} else {
- Log.d(Config.LOGTAG,"could not process KeyTransportMessage");
+ Logging.d(Config.LOGTAG,"could not process KeyTransportMessage");
}
} else if (message.getEncryption() == Message.ENCRYPTION_OTR) {
byte[] key = conversation.getSymmetricKey();
@@ -403,7 +413,7 @@ public class JingleConnection implements Transferable {
} else {
this.file.setExpectedSize(size);
}
- Log.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize());
+ Logging.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize());
} else {
this.sendCancel();
this.fail();
@@ -419,13 +429,13 @@ public class JingleConnection implements Transferable {
Content content = new Content(this.contentCreator, this.contentName);
if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
content.setTransportId(this.transportId);
- this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false);
+ this.file = FileBackend.getFile(message, false);
Pair<InputStream,Integer> pair;
try {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
Conversation conversation = this.message.getConversation();
if (!this.mXmppConnectionService.renewSymmetricKey(conversation)) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not set symmetric key");
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not set symmetric key");
cancel();
}
this.file.setKeyAndIv(conversation.getSymmetricKey());
@@ -457,7 +467,7 @@ public class JingleConnection implements Transferable {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() == IqPacket.TYPE.RESULT) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": other party received offer");
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": other party received offer");
mJingleStatus = JINGLE_STATUS_INITIATED;
mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED);
} else {
@@ -499,7 +509,7 @@ public class JingleConnection implements Transferable {
@Override
public void failed() {
- Log.d(Config.LOGTAG,"connection to our own primary candidate failed");
+ Logging.d(Config.LOGTAG,"connection to our own primary candidate failed");
content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content);
sendJinglePacket(packet);
@@ -508,7 +518,7 @@ public class JingleConnection implements Transferable {
@Override
public void established() {
- Log.d(Config.LOGTAG, "connected to primary candidate");
+ Logging.d(Config.LOGTAG, "connected to primary candidate");
mergeCandidate(candidate);
content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content);
@@ -517,7 +527,7 @@ public class JingleConnection implements Transferable {
}
});
} else {
- Log.d(Config.LOGTAG,"did not find a primary candidate for ourself");
+ Logging.d(Config.LOGTAG,"did not find a primary candidate for ourself");
content.socks5transport().setChildren(getCandidatesAsElements());
packet.setContent(content);
sendJinglePacket(packet);
@@ -563,13 +573,13 @@ public class JingleConnection implements Transferable {
onProxyActivated.success();
} else {
String cid = content.socks5transport().findChild("activated").getAttribute("cid");
- Log.d(Config.LOGTAG, "received proxy activated (" + cid
+ Logging.d(Config.LOGTAG, "received proxy activated (" + cid
+ ")prior to choosing our own transport");
JingleSocks5Transport connection = this.connections.get(cid);
if (connection != null) {
connection.setActivated(true);
} else {
- Log.d(Config.LOGTAG, "activated connection not found");
+ Logging.d(Config.LOGTAG, "activated connection not found");
this.sendCancel();
this.fail();
}
@@ -579,7 +589,7 @@ public class JingleConnection implements Transferable {
onProxyActivated.failed();
return true;
} else if (content.socks5transport().hasChild("candidate-error")) {
- Log.d(Config.LOGTAG, "received candidate error");
+ Logging.d(Config.LOGTAG, "received candidate error");
this.receivedCandidate = true;
if ((mJingleStatus == JINGLE_STATUS_ACCEPTED)
&& (this.sentCandidate)) {
@@ -590,7 +600,7 @@ public class JingleConnection implements Transferable {
String cid = content.socks5transport()
.findChild("candidate-used").getAttribute("cid");
if (cid != null) {
- Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid);
+ Logging.d(Config.LOGTAG, "candidate used by counterpart:" + cid);
JingleCandidate candidate = getCandidate(cid);
candidate.flagAsUsedByCounterpart();
this.receivedCandidate = true;
@@ -598,7 +608,7 @@ public class JingleConnection implements Transferable {
&& (this.sentCandidate)) {
this.connect();
} else {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"ignoring because file is already in transmission or we havent sent our candidate yet");
}
return true;
@@ -617,7 +627,7 @@ public class JingleConnection implements Transferable {
final JingleSocks5Transport connection = chooseConnection();
this.transport = connection;
if (connection == null) {
- Log.d(Config.LOGTAG, "could not find suitable candidate");
+ Logging.d(Config.LOGTAG, "could not find suitable candidate");
this.disconnectSocks5Connections();
if (this.initiator.equals(account.getJid())) {
this.sendFallbackToIbb();
@@ -626,7 +636,7 @@ public class JingleConnection implements Transferable {
this.mJingleStatus = JINGLE_STATUS_TRANSMITTING;
if (connection.needsActivation()) {
if (connection.getCandidate().isOurs()) {
- Log.d(Config.LOGTAG, "candidate "
+ Logging.d(Config.LOGTAG, "candidate "
+ connection.getCandidate().getCid()
+ " was our proxy. going to activate");
IqPacket activation = new IqPacket(IqPacket.TYPE.SET);
@@ -650,17 +660,17 @@ public class JingleConnection implements Transferable {
}
});
} else {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"candidate "
+ connection.getCandidate().getCid()
+ " was a proxy. waiting for other party to activate");
}
} else {
if (initiator.equals(account.getJid())) {
- Log.d(Config.LOGTAG, "we were initiating. sending file");
+ Logging.d(Config.LOGTAG, "we were initiating. sending file");
connection.send(file, onFileTransmissionSatusChanged);
} else {
- Log.d(Config.LOGTAG, "we were responding. receiving file");
+ Logging.d(Config.LOGTAG, "we were responding. receiving file");
connection.receive(file, onFileTransmissionSatusChanged);
}
}
@@ -672,11 +682,11 @@ public class JingleConnection implements Transferable {
for (Entry<String, JingleSocks5Transport> cursor : connections
.entrySet()) {
JingleSocks5Transport currentConnection = cursor.getValue();
- // Log.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString());
+ // Logging.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString());
if (currentConnection.isEstablished()
&& (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection
.getCandidate().isOurs()))) {
- // Log.d(Config.LOGTAG,"is usable");
+ // Logging.d(Config.LOGTAG,"is usable");
if (connection == null) {
connection = currentConnection;
} else {
@@ -685,7 +695,7 @@ public class JingleConnection implements Transferable {
connection = currentConnection;
} else if (connection.getCandidate().getPriority() == currentConnection
.getCandidate().getPriority()) {
- // Log.d(Config.LOGTAG,"found two candidates with same priority");
+ // Logging.d(Config.LOGTAG,"found two candidates with same priority");
if (initiator.equals(account.getJid())) {
if (currentConnection.getCandidate().isOurs()) {
connection = currentConnection;
@@ -717,7 +727,7 @@ public class JingleConnection implements Transferable {
}
private void sendFallbackToIbb() {
- Log.d(Config.LOGTAG, "sending fallback to ibb");
+ Logging.d(Config.LOGTAG, "sending fallback to ibb");
JinglePacket packet = this.bootstrapPacket("transport-replace");
Content content = new Content(this.contentCreator, this.contentName);
this.transportId = this.mJingleConnectionManager.nextRandomId();
@@ -729,7 +739,7 @@ public class JingleConnection implements Transferable {
}
private boolean receiveFallbackToIbb(JinglePacket packet) {
- Log.d(Config.LOGTAG, "receiving fallack to ibb");
+ Logging.d(Config.LOGTAG, "receiving fallack to ibb");
String receivedBlockSize = packet.getJingleContent().ibbTransport()
.getAttribute("block-size");
if (receivedBlockSize != null) {
@@ -765,7 +775,7 @@ public class JingleConnection implements Transferable {
@Override
public void failed() {
- Log.d(Config.LOGTAG, "ibb open failed");
+ Logging.d(Config.LOGTAG, "ibb open failed");
}
@Override
@@ -817,8 +827,8 @@ public class JingleConnection implements Transferable {
if (this.transport != null && this.transport instanceof JingleInbandTransport) {
this.transport.disconnect();
}
- FileBackend.close(mFileInputStream);
- FileBackend.close(mFileOutputStream);
+ StreamUtil.close(mFileInputStream);
+ StreamUtil.close(mFileOutputStream);
if (this.message != null) {
if (this.responder.equals(account.getJid())) {
this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED));
@@ -862,7 +872,7 @@ public class JingleConnection implements Transferable {
@Override
public void failed() {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"connection failed with " + candidate.getHost() + ":"
+ candidate.getPort());
connectNextCandidate();
@@ -870,7 +880,7 @@ public class JingleConnection implements Transferable {
@Override
public void established() {
- Log.d(Config.LOGTAG,
+ Logging.d(Config.LOGTAG,
"established connection with " + candidate.getHost()
+ ":" + candidate.getPort());
sendCandidateUsed(candidate.getCid());
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index 0f0361cd..3be1276d 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -8,9 +8,13 @@ import java.security.SecureRandom;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import android.annotation.SuppressLint;
+
+import de.thedevstack.android.logcat.Logging;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.services.AbstractConnectionManager;
@@ -155,9 +159,9 @@ public class JingleConnectionManager extends AbstractConnectionManager {
}
}
}
- Log.d(Config.LOGTAG,"couldn't deliver payload: " + payload.toString());
+ Logging.d(Config.LOGTAG,"couldn't deliver payload: " + payload.toString());
} else {
- Log.d(Config.LOGTAG, "no sid found in incoming ibb packet");
+ Logging.d(Config.LOGTAG, "no sid found in incoming ibb packet");
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
index 0b0cb408..d1cd20fa 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
@@ -10,6 +10,11 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
+import android.util.Base64;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.utils.StreamUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.DownloadableFile;
@@ -95,13 +100,13 @@ public class JingleInbandTransport extends JingleTransport {
file.createNewFile();
this.fileOutputStream = connection.getFileOutputStream();
if (this.fileOutputStream == null) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not create output stream");
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": could not create output stream");
callback.onFileTransferAborted();
return;
}
this.remainingSize = this.fileSize = file.getExpectedSize();
} catch (final NoSuchAlgorithmException | IOException e) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+" "+e.getMessage());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+" "+e.getMessage());
callback.onFileTransferAborted();
}
}
@@ -118,7 +123,7 @@ public class JingleInbandTransport extends JingleTransport {
this.digest.reset();
fileInputStream = connection.getFileInputStream();
if (fileInputStream == null) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could no create input stream");
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": could no create input stream");
callback.onFileTransferAborted();
return;
}
@@ -127,7 +132,7 @@ public class JingleInbandTransport extends JingleTransport {
}
} catch (NoSuchAlgorithmException e) {
callback.onFileTransferAborted();
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
}
}
@@ -186,8 +191,8 @@ public class JingleInbandTransport extends JingleTransport {
fileInputStream.close();
}
} catch (IOException e) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
- FileBackend.close(fileInputStream);
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
+ StreamUtil.close(fileInputStream);
this.onFileTransmissionStatusChanged.onFileTransferAborted();
}
}
@@ -210,8 +215,8 @@ public class JingleInbandTransport extends JingleTransport {
connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100));
}
} catch (IOException e) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
- FileBackend.close(fileOutputStream);
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": "+e.getMessage());
+ StreamUtil.close(fileOutputStream);
this.onFileTransmissionStatusChanged.onFileTransferAborted();
}
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
index 9240bd2c..c4c96ea2 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
@@ -17,6 +17,9 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.utils.StreamUtil;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.persistance.FileBackend;
@@ -98,7 +101,7 @@ public class JingleSocks5Transport extends JingleTransport {
digest.reset();
fileInputStream = connection.getFileInputStream();
if (fileInputStream == null) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create input stream");
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create input stream");
callback.onFileTransferAborted();
return;
}
@@ -118,16 +121,16 @@ public class JingleSocks5Transport extends JingleTransport {
callback.onFileTransmitted(file);
}
} catch (FileNotFoundException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} catch (IOException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} finally {
- FileBackend.close(fileInputStream);
+ StreamUtil.close(fileInputStream);
wakeLock.release();
}
}
@@ -153,7 +156,7 @@ public class JingleSocks5Transport extends JingleTransport {
fileOutputStream = connection.getFileOutputStream();
if (fileOutputStream == null) {
callback.onFileTransferAborted();
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create output stream");
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create output stream");
return;
}
double size = file.getExpectedSize();
@@ -164,7 +167,7 @@ public class JingleSocks5Transport extends JingleTransport {
count = inputStream.read(buffer);
if (count == -1) {
callback.onFileTransferAborted();
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": file ended prematurely with "+remainingSize+" bytes remaining");
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": file ended prematurely with "+remainingSize+" bytes remaining");
return;
} else {
fileOutputStream.write(buffer, 0, count);
@@ -178,18 +181,18 @@ public class JingleSocks5Transport extends JingleTransport {
file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest()));
callback.onFileTransmitted(file);
} catch (FileNotFoundException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} catch (IOException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
+ Logging.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} finally {
wakeLock.release();
- FileBackend.close(fileOutputStream);
- FileBackend.close(inputStream);
+ StreamUtil.close(fileOutputStream);
+ StreamUtil.close(inputStream);
}
}
}).start();
@@ -204,9 +207,9 @@ public class JingleSocks5Transport extends JingleTransport {
}
public void disconnect() {
- FileBackend.close(inputStream);
- FileBackend.close(outputStream);
- FileBackend.close(socket);
+ StreamUtil.close(inputStream);
+ StreamUtil.close(outputStream);
+ StreamUtil.close(socket);
}
public boolean isEstablished() {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
index 941b4b5f..e7539c62 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
@@ -2,6 +2,8 @@ package eu.siacs.conversations.xmpp.stanzas;
import android.util.Pair;
+import java.text.ParseException;
+
import eu.siacs.conversations.parser.AbstractParser;
import eu.siacs.conversations.xml.Element;