aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/eu/siacs/conversations/Config.java2
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java115
-rw-r--r--src/eu/siacs/conversations/entities/Contact.java1
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java116
-rw-r--r--src/eu/siacs/conversations/entities/Message.java6
-rw-r--r--src/eu/siacs/conversations/entities/MucOptions.java63
-rw-r--r--src/eu/siacs/conversations/entities/Roster.java13
-rw-r--r--src/eu/siacs/conversations/generator/AbstractGenerator.java4
-rw-r--r--src/eu/siacs/conversations/generator/MessageGenerator.java8
-rw-r--r--src/eu/siacs/conversations/parser/AbstractParser.java2
-rw-r--r--src/eu/siacs/conversations/parser/IqParser.java3
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java81
-rw-r--r--src/eu/siacs/conversations/parser/PresenceParser.java6
-rw-r--r--src/eu/siacs/conversations/persistance/DatabaseBackend.java24
-rw-r--r--src/eu/siacs/conversations/persistance/FileBackend.java17
-rw-r--r--src/eu/siacs/conversations/services/EventReceiver.java3
-rw-r--r--src/eu/siacs/conversations/services/ImageProvider.java2
-rw-r--r--src/eu/siacs/conversations/services/NotificationService.java241
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java154
-rw-r--r--src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java2
-rw-r--r--src/eu/siacs/conversations/ui/ContactDetailsActivity.java14
-rw-r--r--src/eu/siacs/conversations/ui/ConversationActivity.java280
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java55
-rw-r--r--src/eu/siacs/conversations/ui/EditAccountActivity.java83
-rw-r--r--src/eu/siacs/conversations/ui/ManageAccountActivity.java8
-rw-r--r--src/eu/siacs/conversations/ui/SettingsActivity.java18
-rw-r--r--src/eu/siacs/conversations/ui/StartConversationActivity.java91
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java18
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java8
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java4
-rw-r--r--src/eu/siacs/conversations/ui/adapter/MessageAdapter.java12
-rw-r--r--src/eu/siacs/conversations/utils/DNSHelper.java8
-rw-r--r--src/eu/siacs/conversations/utils/UIHelper.java178
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java46
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java12
35 files changed, 1111 insertions, 587 deletions
diff --git a/src/eu/siacs/conversations/Config.java b/src/eu/siacs/conversations/Config.java
index 1725eca6..a11e1763 100644
--- a/src/eu/siacs/conversations/Config.java
+++ b/src/eu/siacs/conversations/Config.java
@@ -10,7 +10,7 @@ public final class Config {
public static final int PING_MIN_INTERVAL = 30;
public static final int PING_TIMEOUT = 10;
public static final int CONNECT_TIMEOUT = 90;
- public static final int CARBON_GRACE_PERIOD = 60;
+ public static final int CARBON_GRACE_PERIOD = 120;
public static final int AVATAR_SIZE = 192;
public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP;
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
index 14f010e7..722fb6d9 100644
--- a/src/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -7,46 +7,35 @@ import android.graphics.Bitmap;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
-public class Bookmark implements ListItem {
+public class Bookmark extends Element implements ListItem {
private Account account;
- private String jid;
- private String nick;
- private String name;
- private String password;
- private boolean autojoin;
- private boolean providePassword;
private Conversation mJoinedConversation;
public Bookmark(Account account, String jid) {
+ super("conference");
+ this.setAttribute("jid", jid);
+ this.account = account;
+ }
+
+ private Bookmark(Account account) {
+ super("conference");
this.account = account;
- this.jid = jid;
}
public static Bookmark parse(Element element, Account account) {
- Bookmark bookmark = new Bookmark(account, element.getAttribute("jid"));
- bookmark.setName(element.getAttribute("name"));
- String autojoin = element.getAttribute("autojoin");
- if (autojoin != null
- && (autojoin.equals("true") || autojoin.equals("1"))) {
- bookmark.setAutojoin(true);
- } else {
- bookmark.setAutojoin(false);
- }
- Element nick = element.findChild("nick");
- if (nick != null) {
- bookmark.setNick(nick.getContent());
- }
- Element password = element.findChild("password");
- if (password != null) {
- bookmark.setPassword(password.getContent());
- bookmark.setProvidePassword(true);
- }
+ Bookmark bookmark = new Bookmark(account);
+ bookmark.setAttributes(element.getAttributes());
+ bookmark.setChildren(element.getChildren());
return bookmark;
}
public void setAutojoin(boolean autojoin) {
- this.autojoin = autojoin;
+ if (autojoin) {
+ this.setAttribute("autojoin", "true");
+ } else {
+ this.setAttribute("autojoin", "false");
+ }
}
public void setName(String name) {
@@ -54,15 +43,18 @@ public class Bookmark implements ListItem {
}
public void setNick(String nick) {
- this.nick = nick;
+ Element element = this.findChild("nick");
+ if (element == null) {
+ element = this.addChild("nick");
+ }
+ element.setContent(nick);
}
public void setPassword(String password) {
- this.password = password;
- }
-
- private void setProvidePassword(boolean providePassword) {
- this.providePassword = providePassword;
+ Element element = this.findChild("password");
+ if (element != null) {
+ element.setContent(password);
+ }
}
@Override
@@ -76,32 +68,45 @@ public class Bookmark implements ListItem {
if (this.mJoinedConversation != null
&& (this.mJoinedConversation.getMucOptions().getSubject() != null)) {
return this.mJoinedConversation.getMucOptions().getSubject();
- } else if (name != null) {
- return name;
+ } else if (getName() != null) {
+ return getName();
} else {
- return this.jid.split("@")[0];
+ return this.getJid().split("@")[0];
}
}
@Override
public String getJid() {
- return this.jid.toLowerCase(Locale.US);
+ String jid = this.getAttribute("jid");
+ if (jid != null) {
+ return jid.toLowerCase(Locale.US);
+ } else {
+ return null;
+ }
}
public String getNick() {
- return this.nick;
+ Element nick = this.findChild("nick");
+ if (nick != null) {
+ return nick.getContent();
+ } else {
+ return null;
+ }
}
public boolean autojoin() {
- return autojoin;
+ String autojoin = this.getAttribute("autojoin");
+ return (autojoin != null && (autojoin.equalsIgnoreCase("true") || autojoin
+ .equalsIgnoreCase("1")));
}
public String getPassword() {
- return this.password;
- }
-
- public boolean isProvidePassword() {
- return this.providePassword;
+ Element password = this.findChild("password");
+ if (password != null) {
+ return password.getContent();
+ } else {
+ return null;
+ }
}
public boolean match(String needle) {
@@ -131,27 +136,7 @@ public class Bookmark implements ListItem {
}
public String getName() {
- return name;
- }
-
- public Element toElement() {
- Element element = new Element("conference");
- element.setAttribute("jid", this.getJid());
- if (this.getName() != null) {
- element.setAttribute("name", this.getName());
- }
- if (this.autojoin) {
- element.setAttribute("autojoin", "true");
- } else {
- element.setAttribute("autojoin", "false");
- }
- if (this.nick != null) {
- element.addChild("nick").setContent(this.nick);
- }
- if (this.password != null && isProvidePassword()) {
- element.addChild("password").setContent(this.password);
- }
- return element;
+ return this.getAttribute("name");
}
public void unregisterConversation() {
diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java
index dfd6c059..b1ebe662 100644
--- a/src/eu/siacs/conversations/entities/Contact.java
+++ b/src/eu/siacs/conversations/entities/Contact.java
@@ -156,6 +156,7 @@ public class Contact implements ListItem {
public void clearPresences() {
this.presences.clearPresences();
+ this.resetOption(Options.PENDING_SUBSCRIPTION_REQUEST);
}
public int getMostAvailableStatus() {
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index 8395449d..b4c99dc1 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -4,6 +4,9 @@ import java.security.interfaces.DSAPublicKey;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.UIHelper;
@@ -36,6 +39,11 @@ public class Conversation extends AbstractEntity {
public static final String STATUS = "status";
public static final String CREATED = "created";
public static final String MODE = "mode";
+ public static final String ATTRIBUTES = "attributes";
+
+ public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption";
+ public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password";
+ public static final String ATTRIBUTE_MUTED_TILL = "muted_till";
private String name;
private String contactUuid;
@@ -45,7 +53,7 @@ public class Conversation extends AbstractEntity {
private long created;
private int mode;
- private long mutedTill = 0;
+ private JSONObject attributes = new JSONObject();
private String nextPresence;
@@ -56,12 +64,11 @@ public class Conversation extends AbstractEntity {
private transient String otrFingerprint = null;
- private int nextMessageEncryption = -1;
private String nextMessage;
private transient MucOptions mucOptions = null;
- private transient String latestMarkableMessageId;
+ //private transient String latestMarkableMessageId;
private byte[] symmetricKey;
@@ -73,13 +80,13 @@ public class Conversation extends AbstractEntity {
int mode) {
this(java.util.UUID.randomUUID().toString(), name, null, account
.getUuid(), contactJid, System.currentTimeMillis(),
- STATUS_AVAILABLE, mode);
+ STATUS_AVAILABLE, mode, "");
this.account = account;
}
public Conversation(String uuid, String name, String contactUuid,
String accountUuid, String contactJid, long created, int status,
- int mode) {
+ int mode, String attributes) {
this.uuid = uuid;
this.name = name;
this.contactUuid = contactUuid;
@@ -88,6 +95,14 @@ public class Conversation extends AbstractEntity {
this.created = created;
this.status = status;
this.mode = mode;
+ try {
+ if (attributes == null) {
+ attributes = new String();
+ }
+ this.attributes = new JSONObject(attributes);
+ } catch (JSONException e) {
+ this.attributes = new JSONObject();
+ }
}
public List<Message> getMessages() {
@@ -123,10 +138,20 @@ public class Conversation extends AbstractEntity {
}
}
- public String popLatestMarkableMessageId() {
- String id = this.latestMarkableMessageId;
- this.latestMarkableMessageId = null;
- return id;
+ public String getLatestMarkableMessageId() {
+ if (this.messages == null) {
+ return null;
+ }
+ for(int i = this.messages.size() - 1; i >= 0; --i) {
+ if (this.messages.get(i).getStatus() <= Message.STATUS_RECEIVED && this.messages.get(i).markable) {
+ if (this.messages.get(i).isRead()) {
+ return null;
+ } else {
+ return this.messages.get(i).getRemoteMsgId();
+ }
+ }
+ }
+ return null;
}
public Message getLatestMessage() {
@@ -198,6 +223,7 @@ public class Conversation extends AbstractEntity {
values.put(CREATED, created);
values.put(STATUS, status);
values.put(MODE, mode);
+ values.put(ATTRIBUTES, attributes.toString());
return values;
}
@@ -209,7 +235,8 @@ public class Conversation extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(CONTACTJID)),
cursor.getLong(cursor.getColumnIndex(CREATED)),
cursor.getInt(cursor.getColumnIndex(STATUS)),
- cursor.getInt(cursor.getColumnIndex(MODE)));
+ cursor.getInt(cursor.getColumnIndex(MODE)),
+ cursor.getString(cursor.getColumnIndex(ATTRIBUTES)));
}
public void setStatus(int status) {
@@ -229,8 +256,8 @@ public class Conversation extends AbstractEntity {
if (this.otrSession != null) {
return this.otrSession;
} else {
- SessionID sessionId = new SessionID(
- this.getContactJid().split("/",2)[0], presence, "xmpp");
+ SessionID sessionId = new SessionID(this.getContactJid().split("/",
+ 2)[0], presence, "xmpp");
this.otrSession = new SessionImpl(sessionId, getAccount()
.getOtrEngine(service));
try {
@@ -345,7 +372,8 @@ public class Conversation extends AbstractEntity {
}
public int getNextEncryption(boolean force) {
- if (this.nextMessageEncryption == -1) {
+ int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1);
+ if (next == -1) {
int latest = this.getLatestEncryption();
if (latest == Message.ENCRYPTION_NONE) {
if (force && getMode() == MODE_SINGLE) {
@@ -363,16 +391,16 @@ public class Conversation extends AbstractEntity {
return latest;
}
}
- if (this.nextMessageEncryption == Message.ENCRYPTION_NONE && force
+ if (next == Message.ENCRYPTION_NONE && force
&& getMode() == MODE_SINGLE) {
return Message.ENCRYPTION_OTR;
} else {
- return this.nextMessageEncryption;
+ return next;
}
}
public void setNextEncryption(int encryption) {
- this.nextMessageEncryption = encryption;
+ this.setAttribute(ATTRIBUTE_NEXT_ENCRYPTION, String.valueOf(encryption));
}
public String getNextMessage() {
@@ -387,12 +415,6 @@ public class Conversation extends AbstractEntity {
this.nextMessage = message;
}
- public void setLatestMarkableMessageId(String id) {
- if (id != null) {
- this.latestMarkableMessageId = id;
- }
- }
-
public void setSymmetricKey(byte[] key) {
this.symmetricKey = key;
}
@@ -433,11 +455,55 @@ public class Conversation extends AbstractEntity {
return false;
}
- public void setMutedTill(long mutedTill) {
- this.mutedTill = mutedTill;
+ public void setMutedTill(long value) {
+ this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value));
}
public boolean isMuted() {
- return SystemClock.elapsedRealtime() < this.mutedTill;
+ return SystemClock.elapsedRealtime() < this.getLongAttribute(
+ ATTRIBUTE_MUTED_TILL, 0);
+ }
+
+ public boolean setAttribute(String key, String value) {
+ try {
+ this.attributes.put(key, value);
+ return true;
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ public String getAttribute(String key) {
+ try {
+ return this.attributes.getString(key);
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ public int getIntAttribute(String key, int defaultValue) {
+ String value = this.getAttribute(key);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ }
+
+ public long getLongAttribute(String key, long defaultValue) {
+ String value = this.getAttribute(key);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
}
}
diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java
index 8f9885c5..49482bbc 100644
--- a/src/eu/siacs/conversations/entities/Message.java
+++ b/src/eu/siacs/conversations/entities/Message.java
@@ -57,9 +57,9 @@ public class Message extends AbstractEntity {
protected boolean read = true;
protected String remoteMsgId = null;
- protected transient Conversation conversation = null;
-
- protected transient Downloadable downloadable = null;
+ protected Conversation conversation = null;
+ protected Downloadable downloadable = null;
+ public boolean markable = false;
private Message() {
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index 676fb4f4..12ea4e93 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -15,6 +15,13 @@ public class MucOptions {
public static final int ERROR_NICK_IN_USE = 1;
public static final int ERROR_ROOM_NOT_FOUND = 2;
public static final int ERROR_PASSWORD_REQUIRED = 3;
+ public static final int ERROR_BANNED = 4;
+ public static final int ERROR_MEMBERS_ONLY = 5;
+
+ public static final int KICKED_FROM_ROOM = 9;
+
+ public static final String STATUS_CODE_BANNED = "301";
+ public static final String STATUS_CODE_KICKED = "307";
public interface OnRenameListener {
public void onRename(boolean success);
@@ -108,7 +115,6 @@ public class MucOptions {
private String subject = null;
private String joinnick;
private String password = null;
- private boolean passwordChanged = false;
public MucOptions(Account account) {
this.account = account;
@@ -134,7 +140,7 @@ public class MucOptions {
}
public void processPacket(PresencePacket packet, PgpEngine pgp) {
- String[] fromParts = packet.getFrom().split("/",2);
+ String[] fromParts = packet.getFrom().split("/", 2);
if (fromParts.length >= 2) {
String name = fromParts[1];
String type = packet.getAttribute("type");
@@ -158,10 +164,6 @@ public class MucOptions {
}
aboutToRename = false;
}
- if (conversation.getBookmark() != null
- && conversation.getBookmark().isProvidePassword()) {
- this.passwordChanged = false;
- }
} else {
addUser(user);
}
@@ -179,11 +181,27 @@ public class MucOptions {
x.getContent()));
}
}
+ } else if (type.equals("unavailable") && name.equals(this.joinnick)) {
+ Element x = packet.findChild("x",
+ "http://jabber.org/protocol/muc#user");
+ if (x != null) {
+ Element status = x.findChild("status");
+ if (status != null) {
+ String code = status.getAttribute("code");
+ if (STATUS_CODE_KICKED.equals(code)) {
+ this.isOnline = false;
+ this.error = KICKED_FROM_ROOM;
+ } else if (STATUS_CODE_BANNED.equals(code)) {
+ this.isOnline = false;
+ this.error = ERROR_BANNED;
+ }
+ }
+ }
} else if (type.equals("unavailable")) {
- deleteUser(packet.getAttribute("from").split("/",2)[1]);
+ deleteUser(packet.getAttribute("from").split("/", 2)[1]);
} else if (type.equals("error")) {
Element error = packet.findChild("error");
- if (error.hasChild("conflict")) {
+ if (error != null && error.hasChild("conflict")) {
if (aboutToRename) {
if (renameListener != null) {
renameListener.onRename(false);
@@ -193,12 +211,13 @@ public class MucOptions {
} else {
this.error = ERROR_NICK_IN_USE;
}
- } else if (error.hasChild("not-authorized")) {
- if (conversation.getBookmark() != null
- && conversation.getBookmark().isProvidePassword()) {
- this.passwordChanged = true;
- }
+ } else if (error != null && error.hasChild("not-authorized")) {
this.error = ERROR_PASSWORD_REQUIRED;
+ } else if (error != null && error.hasChild("forbidden")) {
+ this.error = ERROR_BANNED;
+ } else if (error != null
+ && error.hasChild("registration-required")) {
+ this.error = ERROR_MEMBERS_ONLY;
}
}
}
@@ -209,7 +228,7 @@ public class MucOptions {
}
public String getProposedNick() {
- String[] mucParts = conversation.getContactJid().split("/",2);
+ String[] mucParts = conversation.getContactJid().split("/", 2);
if (conversation.getBookmark() != null
&& conversation.getBookmark().getNick() != null) {
return conversation.getBookmark().getNick();
@@ -309,7 +328,7 @@ public class MucOptions {
}
public String getJoinJid() {
- return this.conversation.getContactJid().split("/",2)[0] + "/"
+ return this.conversation.getContactJid().split("/", 2)[0] + "/"
+ this.joinnick;
}
@@ -323,7 +342,9 @@ public class MucOptions {
}
public String getPassword() {
- if (conversation.getBookmark() != null
+ this.password = conversation
+ .getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
+ if (this.password == null && conversation.getBookmark() != null
&& conversation.getBookmark().getPassword() != null) {
return conversation.getBookmark().getPassword();
} else {
@@ -332,16 +353,12 @@ public class MucOptions {
}
public void setPassword(String password) {
- if (conversation.getBookmark() != null
- && conversation.getBookmark().isProvidePassword()) {
+ if (conversation.getBookmark() != null) {
conversation.getBookmark().setPassword(password);
} else {
this.password = password;
}
+ conversation
+ .setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
}
-
- public boolean isPasswordChanged() {
- return this.passwordChanged;
- }
-
} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/entities/Roster.java b/src/eu/siacs/conversations/entities/Roster.java
index f11f0250..b6908793 100644
--- a/src/eu/siacs/conversations/entities/Roster.java
+++ b/src/eu/siacs/conversations/entities/Roster.java
@@ -14,13 +14,18 @@ public class Roster {
this.account = account;
}
- public boolean hasContact(String jid) {
- String cleanJid = jid.split("/",2)[0];
- return contacts.containsKey(cleanJid);
+ public Contact getContactAsShownInRoster(String jid) {
+ String cleanJid = jid.split("/", 2)[0];
+ Contact contact = contacts.get(cleanJid);
+ if (contact != null && contact.showInRoster()) {
+ return contact;
+ } else {
+ return null;
+ }
}
public Contact getContact(String jid) {
- String cleanJid = jid.split("/",2)[0].toLowerCase(Locale.getDefault());
+ String cleanJid = jid.split("/", 2)[0].toLowerCase(Locale.getDefault());
if (contacts.containsKey(cleanJid)) {
return contacts.get(cleanJid);
} else {
diff --git a/src/eu/siacs/conversations/generator/AbstractGenerator.java b/src/eu/siacs/conversations/generator/AbstractGenerator.java
index 61f290e4..c96d116d 100644
--- a/src/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -21,9 +21,9 @@ public abstract class AbstractGenerator {
"urn:xmpp:avatar:metadata+notify" };
public final String IDENTITY_NAME = "Conversations 0.7";
public final String IDENTITY_TYPE = "phone";
-
+
protected XmppConnectionService mXmppConnectionService;
-
+
protected AbstractGenerator(XmppConnectionService service) {
this.mXmppConnectionService = service;
}
diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java
index d4cab3ed..dd833e56 100644
--- a/src/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/eu/siacs/conversations/generator/MessageGenerator.java
@@ -34,7 +34,7 @@ public class MessageGenerator extends AbstractGenerator {
packet.setTo(message.getCounterpart());
packet.setType(MessagePacket.TYPE_CHAT);
} else {
- packet.setTo(message.getCounterpart().split("/",2)[0]);
+ packet.setTo(message.getCounterpart().split("/", 2)[0]);
packet.setType(MessagePacket.TYPE_GROUPCHAT);
}
packet.setFrom(account.getFullJid());
@@ -134,7 +134,7 @@ public class MessageGenerator extends AbstractGenerator {
String subject) {
MessagePacket packet = new MessagePacket();
packet.setType(MessagePacket.TYPE_GROUPCHAT);
- packet.setTo(conversation.getContactJid().split("/",2)[0]);
+ packet.setTo(conversation.getContactJid().split("/", 2)[0]);
Element subjectChild = new Element("subject");
subjectChild.setContent(subject);
packet.addChild(subjectChild);
@@ -148,13 +148,13 @@ public class MessageGenerator extends AbstractGenerator {
packet.setTo(contact);
packet.setFrom(conversation.getAccount().getFullJid());
Element x = packet.addChild("x", "jabber:x:conference");
- x.setAttribute("jid", conversation.getContactJid().split("/",2)[0]);
+ x.setAttribute("jid", conversation.getContactJid().split("/", 2)[0]);
return packet;
}
public MessagePacket invite(Conversation conversation, String contact) {
MessagePacket packet = new MessagePacket();
- packet.setTo(conversation.getContactJid().split("/",2)[0]);
+ packet.setTo(conversation.getContactJid().split("/", 2)[0]);
packet.setFrom(conversation.getAccount().getFullJid());
Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java
index efbf5aef..5541c1c6 100644
--- a/src/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/eu/siacs/conversations/parser/AbstractParser.java
@@ -60,7 +60,7 @@ public abstract class AbstractParser {
protected void updateLastseen(Element packet, Account account,
boolean presenceOverwrite) {
- String[] fromParts = packet.getAttribute("from").split("/",2);
+ String[] fromParts = packet.getAttribute("from").split("/", 2);
String from = fromParts[0];
String presence = null;
if (fromParts.length >= 2) {
diff --git a/src/eu/siacs/conversations/parser/IqParser.java b/src/eu/siacs/conversations/parser/IqParser.java
index 592b77a4..df6754f2 100644
--- a/src/eu/siacs/conversations/parser/IqParser.java
+++ b/src/eu/siacs/conversations/parser/IqParser.java
@@ -73,6 +73,9 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
IqPacket response = mXmppConnectionService.getIqGenerator()
.discoResponse(packet);
account.getXmppConnection().sendIqPacket(response, null);
+ } else if (packet.hasChild("ping", "urn:xmpp:ping")) {
+ IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT);
+ mXmppConnectionService.sendIqPacket(account, response, null);
} else {
if ((packet.getType() == IqPacket.TYPE_GET)
|| (packet.getType() == IqPacket.TYPE_SET)) {
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index 1c77d10d..f8329037 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -1,13 +1,12 @@
package eu.siacs.conversations.parser;
-import android.os.SystemClock;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xml.Element;
@@ -17,9 +16,6 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class MessageParser extends AbstractParser implements
OnMessagePacketReceived {
-
- private long lastCarbonMessageReceived = -(Config.CARBON_GRACE_PERIOD * 1000);
-
public MessageParser(XmppConnectionService service) {
super(service);
}
@@ -28,7 +24,6 @@ public class MessageParser extends AbstractParser implements
String[] fromParts = packet.getFrom().split("/", 2);
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, fromParts[0], false);
- conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
updateLastseen(packet, account, true);
String pgpBody = getPgpBody(packet);
Message finishedMessage;
@@ -41,6 +36,7 @@ public class MessageParser extends AbstractParser implements
Message.STATUS_RECEIVED);
}
finishedMessage.setRemoteMsgId(packet.getId());
+ finishedMessage.markable = isMarkable(packet);
if (conversation.getMode() == Conversation.MODE_MULTI
&& fromParts.length >= 2) {
finishedMessage.setType(Message.TYPE_PRIVATE);
@@ -71,7 +67,7 @@ public class MessageParser extends AbstractParser implements
updateLastseen(packet, account, true);
String body = packet.getBody();
if (body.matches("^\\?OTRv\\d*\\?")) {
- conversation.resetOtrSession();
+ conversation.endOtrIfNeeded();
}
if (!conversation.hasValidOtrSession()) {
if (properlyAddressed) {
@@ -112,13 +108,12 @@ public class MessageParser extends AbstractParser implements
conversation.setSymmetricKey(CryptoHelper.hexToBytes(key));
return null;
}
- conversation
- .setLatestMarkableMessageId(getMarkableMessageId(packet));
Message finishedMessage = new Message(conversation,
packet.getFrom(), body, Message.ENCRYPTION_OTR,
Message.STATUS_RECEIVED);
finishedMessage.setTime(getTimestamp(packet));
finishedMessage.setRemoteMsgId(packet.getId());
+ finishedMessage.markable = isMarkable(packet);
return finishedMessage;
} catch (Exception e) {
String receivedId = packet.getId();
@@ -160,7 +155,6 @@ public class MessageParser extends AbstractParser implements
status = Message.STATUS_RECEIVED;
}
String pgpBody = getPgpBody(packet);
- conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
Message finishedMessage;
if (pgpBody == null) {
finishedMessage = new Message(conversation, counterPart,
@@ -170,6 +164,7 @@ public class MessageParser extends AbstractParser implements
Message.ENCRYPTION_PGP, status);
}
finishedMessage.setRemoteMsgId(packet.getId());
+ finishedMessage.markable = isMarkable(packet);
if (status == Message.STATUS_RECEIVED) {
finishedMessage.setTrueCounterpart(conversation.getMucOptions()
.getTrueCounterpart(counterPart));
@@ -201,10 +196,24 @@ public class MessageParser extends AbstractParser implements
return null;
}
Element message = forwarded.findChild("message");
- if ((message == null) || (!message.hasChild("body"))) {
+ if (message == null) {
+ return null;
+ }
+ if (!message.hasChild("body")) {
if (status == Message.STATUS_RECEIVED
&& message.getAttribute("from") != null) {
parseNonMessage(message, account);
+ } else if (status == Message.STATUS_SEND
+ && message.hasChild("displayed", "urn:xmpp:chat-markers:0")) {
+ String to = message.getAttribute("to");
+ if (to != null) {
+ Conversation conversation = mXmppConnectionService.find(
+ mXmppConnectionService.getConversations(), account,
+ to.split("/")[0]);
+ if (conversation != null) {
+ mXmppConnectionService.markRead(conversation, false);
+ }
+ }
}
return null;
}
@@ -224,8 +233,6 @@ public class MessageParser extends AbstractParser implements
String[] parts = fullJid.split("/", 2);
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, parts[0], false);
- conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
-
String pgpBody = getPgpBody(message);
Message finishedMessage;
if (pgpBody != null) {
@@ -238,6 +245,7 @@ public class MessageParser extends AbstractParser implements
}
finishedMessage.setTime(getTimestamp(message));
finishedMessage.setRemoteMsgId(message.getAttribute("id"));
+ finishedMessage.markable = isMarkable(message);
if (conversation.getMode() == Conversation.MODE_MULTI
&& parts.length >= 2) {
finishedMessage.setType(Message.TYPE_PRIVATE);
@@ -298,6 +306,8 @@ public class MessageParser extends AbstractParser implements
Element password = x.findChild("password");
conversation.getMucOptions().setPassword(
password.getContent());
+ mXmppConnectionService.databaseBackend
+ .updateConversation(conversation);
}
mXmppConnectionService.joinMuc(conversation);
mXmppConnectionService.updateConversationUi();
@@ -313,6 +323,8 @@ public class MessageParser extends AbstractParser implements
if (!conversation.getMucOptions().online()) {
if (password != null) {
conversation.getMucOptions().setPassword(password);
+ mXmppConnectionService.databaseBackend
+ .updateConversation(conversation);
}
mXmppConnectionService.joinMuc(conversation);
mXmppConnectionService.updateConversationUi();
@@ -371,22 +383,18 @@ public class MessageParser extends AbstractParser implements
}
}
- private String getMarkableMessageId(Element message) {
- if (message.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- return message.getAttribute("id");
- } else {
- return null;
- }
+ private boolean isMarkable(Element message) {
+ return message.hasChild("markable", "urn:xmpp:chat-markers:0");
}
@Override
public void onMessagePacketReceived(Account account, MessagePacket packet) {
Message message = null;
- boolean notify = true;
- if (mXmppConnectionService.getPreferences().getBoolean(
- "notification_grace_period_after_carbon_received", true)) {
- notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > (Config.CARBON_GRACE_PERIOD * 1000);
- }
+ boolean notify = mXmppConnectionService.getPreferences().getBoolean(
+ "show_notification", true);
+ boolean alwaysNotifyInConference = notify
+ && mXmppConnectionService.getPreferences().getBoolean(
+ "always_notify_in_conference", false);
this.parseNick(packet, account);
@@ -397,7 +405,9 @@ public class MessageParser extends AbstractParser implements
if (message != null) {
message.markUnread();
}
- } else if (packet.hasChild("body")) {
+ } else if (packet.hasChild("body")
+ && !(packet.hasChild("x",
+ "http://jabber.org/protocol/muc#user"))) {
message = this.parseChat(packet, account);
if (message != null) {
message.markUnread();
@@ -407,10 +417,11 @@ public class MessageParser extends AbstractParser implements
message = this.parseCarbonMessage(packet, account);
if (message != null) {
if (message.getStatus() == Message.STATUS_SEND) {
- lastCarbonMessageReceived = SystemClock
- .elapsedRealtime();
+ mXmppConnectionService.getNotificationService()
+ .activateGracePeriod();
notify = false;
- message.getConversation().markRead();
+ mXmppConnectionService.markRead(
+ message.getConversation(), false);
} else {
message.markUnread();
}
@@ -423,9 +434,14 @@ public class MessageParser extends AbstractParser implements
if (message != null) {
if (message.getStatus() == Message.STATUS_RECEIVED) {
message.markUnread();
+ notify = alwaysNotifyInConference
+ || NotificationService
+ .wasHighlightedOrPrivate(message);
} else {
- message.getConversation().markRead();
- lastCarbonMessageReceived = SystemClock.elapsedRealtime();
+ mXmppConnectionService.markRead(message.getConversation(),
+ false);
+ mXmppConnectionService.getNotificationService()
+ .activateGracePeriod();
notify = false;
}
}
@@ -463,7 +479,10 @@ public class MessageParser extends AbstractParser implements
}
}
notify = notify && !conversation.isMuted();
- mXmppConnectionService.notifyUi(conversation, notify);
+ if (notify) {
+ mXmppConnectionService.getNotificationService().push(message);
+ }
+ mXmppConnectionService.updateConversationUi();
}
private void parseHeadline(MessagePacket packet, Account account) {
diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java
index e240a858..2c3a7dbc 100644
--- a/src/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/eu/siacs/conversations/parser/PresenceParser.java
@@ -22,7 +22,7 @@ public class PresenceParser extends AbstractParser implements
PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine();
if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
Conversation muc = mXmppConnectionService.find(account, packet
- .getAttribute("from").split("/",2)[0]);
+ .getAttribute("from").split("/", 2)[0]);
if (muc != null) {
boolean before = muc.getMucOptions().online();
muc.getMucOptions().processPacket(packet, mPgpEngine);
@@ -32,7 +32,7 @@ public class PresenceParser extends AbstractParser implements
}
} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
Conversation muc = mXmppConnectionService.find(account, packet
- .getAttribute("from").split("/",2)[0]);
+ .getAttribute("from").split("/", 2)[0]);
if (muc != null) {
boolean before = muc.getMucOptions().online();
muc.getMucOptions().processPacket(packet, mPgpEngine);
@@ -58,6 +58,8 @@ public class PresenceParser extends AbstractParser implements
Presences.parseShow(packet.findChild("show")));
} else if (type.equals("unavailable")) {
account.removePresence(fromParts[1]);
+ mXmppConnectionService.getNotificationService()
+ .deactivateGracePeriod();
}
}
} else {
diff --git a/src/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
index 51fd79e5..0991dd2d 100644
--- a/src/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -19,7 +19,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
private static final String DATABASE_NAME = "history";
- private static final int DATABASE_VERSION = 7;
+ private static final int DATABASE_VERSION = 8;
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@@ -50,10 +50,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ " TEXT, " + Conversation.CONTACT + " TEXT, "
+ Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACTJID
+ " TEXT, " + Conversation.CREATED + " NUMBER, "
- + Conversation.STATUS + " NUMBER," + Conversation.MODE
- + " NUMBER," + "FOREIGN KEY(" + Conversation.ACCOUNT
- + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID
- + ") ON DELETE CASCADE);");
+ + Conversation.STATUS + " NUMBER, " + Conversation.MODE
+ + " NUMBER, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY("
+ + Conversation.ACCOUNT + ") REFERENCES " + Account.TABLENAME
+ + "(" + Account.UUID + ") ON DELETE CASCADE);");
db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID
+ " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, "
+ Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART
@@ -96,6 +96,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN "
+ Account.AVATAR + " TEXT");
}
+ if (oldVersion < 8 && newVersion >= 8) {
+ db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN "
+ + Conversation.ATTRIBUTES + " TEXT");
+ }
}
public static synchronized DatabaseBackend getInstance(Context context) {
@@ -206,6 +210,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
while (cursor.moveToNext()) {
list.add(Account.fromCursor(cursor));
}
+ cursor.close();
return list;
}
@@ -221,13 +226,15 @@ public class DatabaseBackend extends SQLiteOpenHelper {
String[] args = { account.getUuid() };
db.delete(Account.TABLENAME, Account.UUID + "=?", args);
}
-
+
public boolean hasEnabledAccounts() {
SQLiteDatabase db = this.getReadableDatabase();
- Cursor cursor= db.rawQuery("select count("+Account.UUID+") from "+Account.TABLENAME+" where not options & (1 <<1)", null);
+ Cursor cursor = db.rawQuery("select count(" + Account.UUID + ") from "
+ + Account.TABLENAME + " where not options & (1 <<1)", null);
cursor.moveToFirst();
int count = cursor.getInt(0);
- return (count>0);
+ cursor.close();
+ return (count > 0);
}
@Override
@@ -253,6 +260,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
while (cursor.moveToNext()) {
roster.initContact(Contact.fromCursor(cursor));
}
+ cursor.close();
}
public void writeRoster(Roster roster) {
diff --git a/src/eu/siacs/conversations/persistance/FileBackend.java b/src/eu/siacs/conversations/persistance/FileBackend.java
index 2b2aa86e..d86c0ee1 100644
--- a/src/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/eu/siacs/conversations/persistance/FileBackend.java
@@ -250,7 +250,10 @@ public class FileBackend {
if (!file.exists()) {
file = getJingleFileLegacy(message);
}
- Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath());
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inSampleSize = calcSampleSize(file, size);
+ Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),
+ options);
if (fullsize == null) {
throw new FileNotFoundException();
}
@@ -414,6 +417,17 @@ public class FileBackend {
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(context.getContentResolver()
.openInputStream(image), null, options);
+ return calcSampleSize(options, size);
+ }
+
+ private int calcSampleSize(File image, int size) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(image.getAbsolutePath(), options);
+ return calcSampleSize(options, size);
+ }
+
+ private int calcSampleSize(BitmapFactory.Options options, int size) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
@@ -428,7 +442,6 @@ public class FileBackend {
}
}
return inSampleSize;
-
}
public Uri getJingleFileUri(Message message) {
diff --git a/src/eu/siacs/conversations/services/EventReceiver.java b/src/eu/siacs/conversations/services/EventReceiver.java
index e2445b2a..dfbe9db7 100644
--- a/src/eu/siacs/conversations/services/EventReceiver.java
+++ b/src/eu/siacs/conversations/services/EventReceiver.java
@@ -15,7 +15,8 @@ public class EventReceiver extends BroadcastReceiver {
} else {
mIntentForService.setAction("other");
}
- if (intent.getAction().equals("ui") || DatabaseBackend.getInstance(context).hasEnabledAccounts()) {
+ if (intent.getAction().equals("ui")
+ || DatabaseBackend.getInstance(context).hasEnabledAccounts()) {
context.startService(mIntentForService);
}
}
diff --git a/src/eu/siacs/conversations/services/ImageProvider.java b/src/eu/siacs/conversations/services/ImageProvider.java
index af8ab4b2..ac78a454 100644
--- a/src/eu/siacs/conversations/services/ImageProvider.java
+++ b/src/eu/siacs/conversations/services/ImageProvider.java
@@ -31,7 +31,7 @@ public class ImageProvider extends ContentProvider {
if (uuids == null) {
throw new FileNotFoundException();
}
- String[] uuidsSplited = uuids.split("/",2);
+ String[] uuidsSplited = uuids.split("/", 2);
if (uuidsSplited.length != 3) {
throw new FileNotFoundException();
}
diff --git a/src/eu/siacs/conversations/services/NotificationService.java b/src/eu/siacs/conversations/services/NotificationService.java
new file mode 100644
index 00000000..41656707
--- /dev/null
+++ b/src/eu/siacs/conversations/services/NotificationService.java
@@ -0,0 +1,241 @@
+package eu.siacs.conversations.services;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.TaskStackBuilder;
+import android.text.Html;
+
+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.ui.ConversationActivity;
+
+public class NotificationService {
+
+ private XmppConnectionService mXmppConnectionService;
+ private NotificationManager mNotificationManager;
+
+ private LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<String, ArrayList<Message>>();
+
+ public int NOTIFICATION_ID = 0x2342;
+ private Conversation mOpenConversation;
+ private boolean mIsInForeground;
+
+ private long mEndGracePeriod = 0L;
+
+ public NotificationService(XmppConnectionService service) {
+ this.mXmppConnectionService = service;
+ this.mNotificationManager = (NotificationManager) service
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ public synchronized void push(Message message) {
+
+ PowerManager pm = (PowerManager) mXmppConnectionService
+ .getSystemService(Context.POWER_SERVICE);
+ boolean isScreenOn = pm.isScreenOn();
+ if (this.mIsInForeground && isScreenOn
+ && this.mOpenConversation == message.getConversation()) {
+ return;
+ }
+ String conversationUuid = message.getConversationUuid();
+ if (notifications.containsKey(conversationUuid)) {
+ notifications.get(conversationUuid).add(message);
+ } else {
+ ArrayList<Message> mList = new ArrayList<Message>();
+ mList.add(message);
+ notifications.put(conversationUuid, mList);
+ }
+ updateNotification((!(this.mIsInForeground && this.mOpenConversation == null) || !isScreenOn)
+ && !inGracePeriod());
+ }
+
+ public void clear() {
+ notifications.clear();
+ updateNotification(false);
+ }
+
+ public void clear(Conversation conversation) {
+ notifications.remove(conversation.getUuid());
+ updateNotification(false);
+ }
+
+ private void updateNotification(boolean notify) {
+ SharedPreferences preferences = mXmppConnectionService.getPreferences();
+
+ String ringtone = preferences.getString("notification_ringtone", null);
+ boolean vibrate = preferences.getBoolean("vibrate_on_notification",
+ true);
+
+ if (notifications.size() == 0) {
+ mNotificationManager.cancel(NOTIFICATION_ID);
+ } else {
+ NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
+ mXmppConnectionService);
+ mBuilder.setSmallIcon(R.drawable.ic_notification);
+ if (notifications.size() == 1) {
+ ArrayList<Message> messages = notifications.values().iterator()
+ .next();
+ if (messages.size() >= 1) {
+ Conversation conversation = messages.get(0)
+ .getConversation();
+ mBuilder.setLargeIcon(conversation.getImage(
+ mXmppConnectionService, 64));
+ mBuilder.setContentTitle(conversation.getName());
+ StringBuilder text = new StringBuilder();
+ for (int i = 0; i < messages.size(); ++i) {
+ text.append(messages.get(i).getReadableBody(
+ mXmppConnectionService));
+ if (i != messages.size() - 1) {
+ text.append("\n");
+ }
+ }
+ mBuilder.setStyle(new NotificationCompat.BigTextStyle()
+ .bigText(text.toString()));
+ mBuilder.setContentText(messages.get(0).getReadableBody(
+ mXmppConnectionService));
+ if (notify) {
+ mBuilder.setTicker(messages.get(messages.size() - 1)
+ .getReadableBody(mXmppConnectionService));
+ }
+ mBuilder.setContentIntent(createContentIntent(conversation
+ .getUuid()));
+ } else {
+ mNotificationManager.cancel(NOTIFICATION_ID);
+ return;
+ }
+ } else {
+ NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
+ style.setBigContentTitle(notifications.size()
+ + " "
+ + mXmppConnectionService
+ .getString(R.string.unread_conversations));
+ StringBuilder names = new StringBuilder();
+ Conversation conversation = null;
+ for (ArrayList<Message> messages : notifications.values()) {
+ if (messages.size() > 0) {
+ conversation = messages.get(0).getConversation();
+ String name = conversation.getName();
+ style.addLine(Html.fromHtml("<b>"
+ + name
+ + "</b> "
+ + messages.get(0).getReadableBody(
+ mXmppConnectionService)));
+ names.append(name);
+ names.append(", ");
+ }
+ }
+ if (names.length() >= 2) {
+ names.delete(names.length() - 2, names.length());
+ }
+ mBuilder.setContentTitle(notifications.size()
+ + " "
+ + mXmppConnectionService
+ .getString(R.string.unread_conversations));
+ mBuilder.setContentText(names.toString());
+ mBuilder.setStyle(style);
+ if (conversation != null) {
+ mBuilder.setContentIntent(createContentIntent(conversation
+ .getUuid()));
+ }
+ }
+ if (notify) {
+ if (vibrate) {
+ int dat = 70;
+ long[] pattern = { 0, 3 * dat, dat, dat };
+ mBuilder.setVibrate(pattern);
+ }
+ if (ringtone != null) {
+ mBuilder.setSound(Uri.parse(ringtone));
+ }
+ }
+ mBuilder.setDeleteIntent(createDeleteIntent());
+ if (!inGracePeriod()) {
+ mBuilder.setLights(0xffffffff, 2000, 4000);
+ }
+ Notification notification = mBuilder.build();
+ mNotificationManager.notify(NOTIFICATION_ID, notification);
+ }
+ }
+
+ private PendingIntent createContentIntent(String conversationUuid) {
+ TaskStackBuilder stackBuilder = TaskStackBuilder
+ .create(mXmppConnectionService);
+ stackBuilder.addParentStack(ConversationActivity.class);
+
+ Intent viewConversationIntent = new Intent(mXmppConnectionService,
+ ConversationActivity.class);
+ viewConversationIntent.setAction(Intent.ACTION_VIEW);
+ viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
+ conversationUuid);
+ viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
+
+ stackBuilder.addNextIntent(viewConversationIntent);
+
+ PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ return resultPendingIntent;
+ }
+
+ private PendingIntent createDeleteIntent() {
+ Intent intent = new Intent(mXmppConnectionService,
+ XmppConnectionService.class);
+ intent.setAction("clear_notification");
+ return PendingIntent.getService(mXmppConnectionService, 0, intent, 0);
+ }
+
+ public static boolean wasHighlightedOrPrivate(Message message) {
+ String nick = message.getConversation().getMucOptions().getActualNick();
+ Pattern highlight = generateNickHighlightPattern(nick);
+ if (message.getBody() == null || nick == null) {
+ return false;
+ }
+ Matcher m = highlight.matcher(message.getBody());
+ return (m.find() || message.getType() == Message.TYPE_PRIVATE);
+ }
+
+ private static Pattern generateNickHighlightPattern(String nick) {
+ // We expect a word boundary, i.e. space or start of string, followed by
+ // the
+ // nick (matched in case-insensitive manner), followed by optional
+ // punctuation (for example "bob: i disagree" or "how are you alice?"),
+ // followed by another word boundary.
+ return Pattern.compile("\\b" + nick + "\\p{Punct}?\\b",
+ Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ }
+
+ public void setOpenConversation(Conversation conversation) {
+ this.mOpenConversation = conversation;
+ }
+
+ public void setIsInForeground(boolean foreground) {
+ this.mIsInForeground = foreground;
+ }
+
+ public void activateGracePeriod() {
+ this.mEndGracePeriod = SystemClock.elapsedRealtime()
+ + (Config.CARBON_GRACE_PERIOD * 1000);
+ }
+
+ public void deactivateGracePeriod() {
+ this.mEndGracePeriod = 0L;
+ }
+
+ private boolean inGracePeriod() {
+ return SystemClock.elapsedRealtime() < this.mEndGracePeriod;
+ }
+}
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index db3ee2b9..e6297f4f 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -90,9 +90,12 @@ public class XmppConnectionService extends Service {
public long startDate;
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+ public static String ACTION_CLEAR_NOTIFICATION = "clear_notification";
private MemorizingTrustManager mMemorizingTrustManager;
+ private NotificationService mNotificationService;
+
private MessageParser mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this);
private IqParser mIqParser = new IqParser(this);
@@ -316,14 +319,16 @@ public class XmppConnectionService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- if ((intent != null)
- && (ACTION_MERGE_PHONE_CONTACTS.equals(intent.getAction()))) {
- mergePhoneContactsWithRoster();
- return START_STICKY;
- } else if ((intent != null)
- && (Intent.ACTION_SHUTDOWN.equals(intent.getAction()))) {
- logoutAndSave();
- return START_NOT_STICKY;
+ if (intent != null && intent.getAction() != null) {
+ if (intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS)) {
+ mergePhoneContactsWithRoster();
+ return START_STICKY;
+ } else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
+ logoutAndSave();
+ return START_NOT_STICKY;
+ } else if (intent.getAction().equals(ACTION_CLEAR_NOTIFICATION)) {
+ mNotificationService.clear();
+ }
}
this.wakeLock.acquire();
ConnectivityManager cm = (ConnectivityManager) getApplicationContext()
@@ -401,6 +406,7 @@ public class XmppConnectionService extends Service {
this.mRandom = new SecureRandom();
this.mMemorizingTrustManager = new MemorizingTrustManager(
getApplicationContext());
+ this.mNotificationService = new NotificationService(this);
this.databaseBackend = DatabaseBackend
.getInstance(getApplicationContext());
this.fileBackend = new FileBackend(getApplicationContext());
@@ -511,7 +517,8 @@ public class XmppConnectionService extends Service {
MessagePacket packet = null;
boolean saveInDb = true;
boolean send = false;
- if (account.getStatus() == Account.STATUS_ONLINE) {
+ if (account.getStatus() == Account.STATUS_ONLINE
+ && account.getXmppConnection() != null) {
if (message.getType() == Message.TYPE_IMAGE) {
if (message.getPresence() != null) {
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
@@ -561,6 +568,10 @@ public class XmppConnectionService extends Service {
send = true;
}
}
+ if (!account.getXmppConnection().getFeatures().sm()
+ && conv.getMode() != Conversation.MODE_MULTI) {
+ message.setStatus(Message.STATUS_SEND);
+ }
} else {
message.setStatus(Message.STATUS_WAITING);
if (message.getType() == Message.TYPE_TEXT) {
@@ -586,10 +597,6 @@ public class XmppConnectionService extends Service {
}
conv.getMessages().add(message);
- if (!account.getXmppConnection().getFeatures().sm()
- && conv.getMode() != Conversation.MODE_MULTI) {
- message.setStatus(Message.STATUS_SEND);
- }
if (saveInDb) {
if (message.getEncryption() == Message.ENCRYPTION_NONE
|| saveEncryptedMessages()) {
@@ -742,7 +749,7 @@ public class XmppConnectionService extends Service {
Element query = iqPacket.query("jabber:iq:private");
Element storage = query.addChild("storage", "storage:bookmarks");
for (Bookmark bookmark : account.getBookmarks()) {
- storage.addChild(bookmark.toElement());
+ storage.addChild(bookmark);
}
sendIqPacket(account, iqPacket, null);
}
@@ -824,7 +831,7 @@ public class XmppConnectionService extends Service {
}
});
}
-
+
public int loadMoreMessages(Conversation conversation, long timestamp) {
List<Message> messages = databaseBackend.getMessages(conversation, 50,
timestamp);
@@ -851,8 +858,9 @@ public class XmppConnectionService extends Service {
public Conversation find(List<Conversation> haystack, Account account,
String jid) {
for (Conversation conversation : haystack) {
- if ((conversation.getAccount().equals(account))
- && (conversation.getContactJid().split("/",2)[0].equals(jid))) {
+ if ((account == null || conversation.getAccount().equals(account))
+ && (conversation.getContactJid().split("/", 2)[0]
+ .equals(jid))) {
return conversation;
}
}
@@ -901,10 +909,12 @@ public class XmppConnectionService extends Service {
public void archiveConversation(Conversation conversation) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
- Bookmark bookmark = conversation.getBookmark();
- if (bookmark != null && bookmark.autojoin()) {
- bookmark.setAutojoin(false);
- pushBookmarks(bookmark.getAccount());
+ if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark != null && bookmark.autojoin()) {
+ bookmark.setAutojoin(false);
+ pushBookmarks(bookmark.getAccount());
+ }
}
leaveMuc(conversation);
} else {
@@ -963,10 +973,12 @@ public class XmppConnectionService extends Service {
public void setOnConversationListChangedListener(
OnConversationUpdate listener) {
+ this.mNotificationService.deactivateGracePeriod();
if (checkListeners()) {
switchToForeground();
}
this.mOnConversationUpdate = listener;
+ this.mNotificationService.setIsInForeground(true);
this.convChangedListenerCount++;
}
@@ -974,6 +986,7 @@ public class XmppConnectionService extends Service {
this.convChangedListenerCount--;
if (this.convChangedListenerCount == 0) {
this.mOnConversationUpdate = null;
+ this.mNotificationService.setIsInForeground(false);
if (checkListeners()) {
switchToBackground();
}
@@ -981,6 +994,7 @@ public class XmppConnectionService extends Service {
}
public void setOnAccountListChangedListener(OnAccountUpdate listener) {
+ this.mNotificationService.deactivateGracePeriod();
if (checkListeners()) {
switchToForeground();
}
@@ -999,6 +1013,7 @@ public class XmppConnectionService extends Service {
}
public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ this.mNotificationService.deactivateGracePeriod();
if (checkListeners()) {
switchToForeground();
}
@@ -1111,13 +1126,11 @@ public class XmppConnectionService extends Service {
public void providePasswordForMuc(Conversation conversation, String password) {
if (conversation.getMode() == Conversation.MODE_MULTI) {
conversation.getMucOptions().setPassword(password);
- if (conversation.getBookmark() != null
- && conversation.getMucOptions().isPasswordChanged()) {
- if (!conversation.getBookmark().autojoin()) {
- conversation.getBookmark().setAutojoin(true);
- }
+ if (conversation.getBookmark() != null) {
+ conversation.getBookmark().setAutojoin(true);
pushBookmarks(conversation.getAccount());
}
+ databaseBackend.updateConversation(conversation);
joinMuc(conversation);
}
}
@@ -1266,7 +1279,7 @@ public class XmppConnectionService extends Service {
}
}
}
- notifyUi(conversation, false);
+ updateConversationUi();
}
public boolean renewSymmetricKey(Conversation conversation) {
@@ -1498,6 +1511,9 @@ public class XmppConnectionService extends Service {
thread.start();
scheduleWakeupCall((int) (Config.CONNECT_TIMEOUT * 1.2),
false);
+ } else {
+ account.getRoster().clearPresences();
+ account.setXmppConnection(null);
}
}
}).start();
@@ -1523,24 +1539,34 @@ public class XmppConnectionService extends Service {
public boolean markMessage(Account account, String recipient, String uuid,
int status) {
- for (Conversation conversation : getConversations()) {
- if (conversation.getContactJid().equals(recipient)
- && conversation.getAccount().equals(account)) {
- return markMessage(conversation, uuid, status);
+ if (uuid == null) {
+ return false;
+ } else {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getContactJid().equals(recipient)
+ && conversation.getAccount().equals(account)) {
+ return markMessage(conversation, uuid, status);
+ }
}
+ return false;
}
- return false;
}
public boolean markMessage(Conversation conversation, String uuid,
int status) {
- for (Message message : conversation.getMessages()) {
- if (message.getUuid().equals(uuid)) {
- markMessage(message, status);
- return true;
+ if (uuid == null) {
+ return false;
+ } else {
+ for (Message message : conversation.getMessages()) {
+ if (uuid.equals(message.getUuid())
+ || (message.getStatus() >= Message.STATUS_SEND && uuid
+ .equals(message.getRemoteMsgId()))) {
+ markMessage(message, status);
+ return true;
+ }
}
+ return false;
}
- return false;
}
public void markMessage(Message message, int status) {
@@ -1575,15 +1601,6 @@ public class XmppConnectionService extends Service {
return getPreferences().getBoolean("indicate_received", false);
}
- public void notifyUi(Conversation conversation, boolean notify) {
- if (mOnConversationUpdate != null) {
- mOnConversationUpdate.onConversationUpdate();
- } else {
- UIHelper.updateNotification(getApplicationContext(),
- getConversations(), conversation, notify);
- }
- }
-
public void updateConversationUi() {
if (mOnConversationUpdate != null) {
mOnConversationUpdate.onConversationUpdate();
@@ -1620,15 +1637,21 @@ public class XmppConnectionService extends Service {
return null;
}
- public void markRead(Conversation conversation) {
+ public void markRead(Conversation conversation, boolean calledByUi) {
+ mNotificationService.clear(conversation);
+ String id = conversation.getLatestMarkableMessageId();
conversation.markRead();
- String id = conversation.popLatestMarkableMessageId();
- if (confirmMessages() && id != null) {
+ if (confirmMessages() && id != null && calledByUi) {
+ Log.d(Config.LOGTAG, conversation.getAccount().getJid()
+ + ": sending read marker for " + conversation.getName());
Account account = conversation.getAccount();
String to = conversation.getContactJid();
this.sendMessagePacket(conversation.getAccount(),
mMessageGenerator.confirm(account, to, id));
}
+ if (!calledByUi) {
+ updateConversationUi();
+ }
}
public void failWaitingOtrMessages(Conversation conversation) {
@@ -1703,16 +1726,25 @@ public class XmppConnectionService extends Service {
}
public void sendMessagePacket(Account account, MessagePacket packet) {
- account.getXmppConnection().sendMessagePacket(packet);
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null) {
+ connection.sendMessagePacket(packet);
+ }
}
public void sendPresencePacket(Account account, PresencePacket packet) {
- account.getXmppConnection().sendPresencePacket(packet);
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null) {
+ connection.sendPresencePacket(packet);
+ }
}
public void sendIqPacket(Account account, IqPacket packet,
OnIqPacketReceived callback) {
- account.getXmppConnection().sendIqPacket(packet, callback);
+ XmppConnection connection = account.getXmppConnection();
+ if (connection != null) {
+ connection.sendIqPacket(packet, callback);
+ }
}
public MessageGenerator getMessageGenerator() {
@@ -1742,4 +1774,22 @@ public class XmppConnectionService extends Service {
public interface OnRosterUpdate {
public void onRosterUpdate();
}
+
+ public List<Contact> findContacts(String jid) {
+ ArrayList<Contact> contacts = new ArrayList<Contact>();
+ for (Account account : getAccounts()) {
+ if (!account.isOptionSet(Account.OPTION_DISABLED)) {
+ Contact contact = account.getRoster()
+ .getContactAsShownInRoster(jid);
+ if (contact != null) {
+ contacts.add(contact);
+ }
+ }
+ }
+ return contacts;
+ }
+
+ public NotificationService getNotificationService() {
+ return this.mNotificationService;
+ }
}
diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index 76c12a47..04059d52 100644
--- a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -201,7 +201,7 @@ public class ConferenceDetailsActivity extends XmppActivity {
private void populateView() {
mYourPhoto.setImageBitmap(conversation.getAccount().getImage(this, 48));
setTitle(conversation.getName());
- mFullJid.setText(conversation.getContactJid().split("/",2)[0]);
+ mFullJid.setText(conversation.getContactJid().split("/", 2)[0]);
mYourNick.setText(conversation.getMucOptions().getActualNick());
mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
if (conversation.getMucOptions().online()) {
diff --git a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 9d384c60..9926e126 100644
--- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -39,8 +39,6 @@ import eu.siacs.conversations.utils.UIHelper;
public class ContactDetailsActivity extends XmppActivity {
public static final String ACTION_VIEW_CONTACT = "view_contact";
- protected ContactDetailsActivity activity = this;
-
private Contact contact;
private String accountJid;
@@ -58,8 +56,8 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
public void onClick(DialogInterface dialog, int which) {
- activity.xmppConnectionService.deleteContactOnServer(contact);
- activity.finish();
+ ContactDetailsActivity.this.xmppConnectionService.deleteContactOnServer(contact);
+ ContactDetailsActivity.this.finish();
}
};
@@ -73,14 +71,14 @@ public class ContactDetailsActivity extends XmppActivity {
intent.putExtra(Intents.Insert.IM_PROTOCOL,
CommonDataKinds.Im.PROTOCOL_JABBER);
intent.putExtra("finishActivityOnSaveCompleted", true);
- activity.startActivityForResult(intent, 0);
+ ContactDetailsActivity.this.startActivityForResult(intent, 0);
}
};
private OnClickListener onBadgeClick = new OnClickListener() {
@Override
public void onClick(View v) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ AlertDialog.Builder builder = new AlertDialog.Builder(ContactDetailsActivity.this);
builder.setTitle(getString(R.string.action_add_phone_book));
builder.setMessage(getString(R.string.add_phone_book_text,
contact.getJid()));
@@ -206,7 +204,7 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
public void onValueEdited(String value) {
contact.setServerName(value);
- activity.xmppConnectionService
+ ContactDetailsActivity.this.xmppConnectionService
.pushContactToServer(contact);
populateView();
}
@@ -354,7 +352,7 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
public void onClick(View v) {
- PgpEngine pgp = activity.xmppConnectionService
+ PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService
.getPgpEngine();
if (pgp != null) {
PendingIntent intent = pgp.getIntentForKey(contact);
diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java
index 89d823a1..ad1cd283 100644
--- a/src/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/ConversationActivity.java
@@ -12,11 +12,11 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.utils.ExceptionHelper;
-import eu.siacs.conversations.utils.UIHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.MediaStore;
+import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.FragmentTransaction;
@@ -59,8 +59,13 @@ public class ConversationActivity extends XmppActivity implements
private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0303;
+ private static final String STATE_OPEN_CONVERSATION = "state_open_conversation";
+ private static final String STATE_PANEL_OPEN = "state_panel_open";
- protected SlidingPaneLayout spl;
+ private String mOpenConverstaion = null;
+ private boolean mPanelOpen = true;
+
+ private View mContentView;
private List<Conversation> conversationList = new ArrayList<Conversation>();
private Conversation selectedConversation = null;
@@ -69,7 +74,6 @@ public class ConversationActivity extends XmppActivity implements
private boolean paneShouldBeOpen = true;
private ArrayAdapter<Conversation> listAdapter;
- protected ConversationActivity activity = this;
private Toast prepareImageToast;
private Uri pendingImageUri = null;
@@ -90,18 +94,52 @@ public class ConversationActivity extends XmppActivity implements
return this.listView;
}
- public SlidingPaneLayout getSlidingPaneLayout() {
- return this.spl;
- }
-
public boolean shouldPaneBeOpen() {
return paneShouldBeOpen;
}
+ public void showConversationsOverview() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.openPane();
+ }
+ }
+
+ public void hideConversationsOverview() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.closePane();
+ }
+ }
+
+ public boolean isConversationsOverviewHideable() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ return mSlidingPaneLayout.isSlideable();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isConversationsOverviewVisable() {
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ return mSlidingPaneLayout.isOpen();
+ } else {
+ return true;
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mOpenConverstaion = savedInstanceState.getString(
+ STATE_OPEN_CONVERSATION, null);
+ mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
+ }
+
setContentView(R.layout.fragment_conversations_overview);
listView = (ListView) findViewById(R.id.list);
@@ -122,63 +160,80 @@ public class ConversationActivity extends XmppActivity implements
setSelectedConversation(conversationList.get(position));
swapConversationFragment();
} else {
- spl.closePane();
+ hideConversationsOverview();
}
}
});
- spl = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout);
- spl.setParallaxDistance(150);
- spl.setShadowResource(R.drawable.es_slidingpane_shadow);
- spl.setSliderFadeColor(0);
- spl.setPanelSlideListener(new PanelSlideListener() {
-
- @Override
- public void onPanelOpened(View arg0) {
- paneShouldBeOpen = true;
- ActionBar ab = getActionBar();
- if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(false);
- ab.setHomeButtonEnabled(false);
- ab.setTitle(R.string.app_name);
- }
- invalidateOptionsMenu();
- hideKeyboard();
- }
+ mContentView = findViewById(R.id.content_view_spl);
+ if (mContentView == null) {
+ mContentView = findViewById(R.id.content_view_ll);
+ }
+ if (mContentView instanceof SlidingPaneLayout) {
+ SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView;
+ mSlidingPaneLayout.setParallaxDistance(150);
+ mSlidingPaneLayout
+ .setShadowResource(R.drawable.es_slidingpane_shadow);
+ mSlidingPaneLayout.setSliderFadeColor(0);
+ mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() {
- @Override
- public void onPanelClosed(View arg0) {
- paneShouldBeOpen = false;
- if ((conversationList.size() > 0)
- && (getSelectedConversation() != null)) {
+ @Override
+ public void onPanelOpened(View arg0) {
+ paneShouldBeOpen = true;
ActionBar ab = getActionBar();
if (ab != null) {
- ab.setDisplayHomeAsUpEnabled(true);
- ab.setHomeButtonEnabled(true);
- if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE
- || activity.useSubjectToIdentifyConference()) {
- ab.setTitle(getSelectedConversation().getName());
- } else {
- ab.setTitle(getSelectedConversation()
- .getContactJid().split("/")[0]);
- }
+ ab.setDisplayHomeAsUpEnabled(false);
+ ab.setHomeButtonEnabled(false);
+ ab.setTitle(R.string.app_name);
}
invalidateOptionsMenu();
- if (!getSelectedConversation().isRead()) {
- xmppConnectionService
- .markRead(getSelectedConversation());
- UIHelper.updateNotification(getApplicationContext(),
- getConversationList(), null, false);
- listView.invalidateViews();
+ hideKeyboard();
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.getNotificationService()
+ .setOpenConversation(null);
}
}
- }
- @Override
- public void onPanelSlide(View arg0, float arg1) {
- // TODO Auto-generated method stub
+ @Override
+ public void onPanelClosed(View arg0) {
+ paneShouldBeOpen = false;
+ if ((conversationList.size() > 0)
+ && (getSelectedConversation() != null)) {
+ openConversation(getSelectedConversation());
+ if (!getSelectedConversation().isRead()) {
+ xmppConnectionService.markRead(
+ getSelectedConversation(), true);
+ listView.invalidateViews();
+ }
+ }
+ }
+
+ @Override
+ public void onPanelSlide(View arg0, float arg1) {
+ // TODO Auto-generated method stub
+
+ }
+ });
+ }
+ }
+ public void openConversation(Conversation conversation) {
+ ActionBar ab = getActionBar();
+ if (ab != null) {
+ ab.setDisplayHomeAsUpEnabled(true);
+ ab.setHomeButtonEnabled(true);
+ if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE
+ || ConversationActivity.this.useSubjectToIdentifyConference()) {
+ ab.setTitle(getSelectedConversation().getName());
+ } else {
+ ab.setTitle(getSelectedConversation().getContactJid()
+ .split("/")[0]);
}
- });
+ }
+ invalidateOptionsMenu();
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.getNotificationService().setOpenConversation(
+ conversation);
+ }
}
@Override
@@ -198,7 +253,8 @@ public class ConversationActivity extends XmppActivity implements
.findItem(R.id.action_invite);
MenuItem menuMute = (MenuItem) menu.findItem(R.id.action_mute);
- if ((spl.isOpen() && (spl.isSlideable()))) {
+ if (isConversationsOverviewVisable()
+ && isConversationsOverviewHideable()) {
menuArchive.setVisible(false);
menuMucDetails.setVisible(false);
menuContactDetails.setVisible(false);
@@ -208,7 +264,7 @@ public class ConversationActivity extends XmppActivity implements
menuClearHistory.setVisible(false);
menuMute.setVisible(false);
} else {
- menuAdd.setVisible(!spl.isSlideable());
+ menuAdd.setVisible(!isConversationsOverviewHideable());
if (this.getSelectedConversation() != null) {
if (this.getSelectedConversation().getLatestMessage()
.getEncryption() != Message.ENCRYPTION_NONE) {
@@ -296,6 +352,8 @@ public class ConversationActivity extends XmppActivity implements
int which) {
conversation
.setNextEncryption(Message.ENCRYPTION_NONE);
+ xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
selectPresenceToAttachFile(attachmentChoice);
}
});
@@ -315,7 +373,7 @@ public class ConversationActivity extends XmppActivity implements
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
- spl.openPane();
+ showConversationsOverview();
return true;
} else if (item.getItemId() == R.id.action_add) {
startActivity(new Intent(this, StartConversationActivity.class));
@@ -367,7 +425,7 @@ public class ConversationActivity extends XmppActivity implements
public void endConversation(Conversation conversation) {
conversation.setStatus(Conversation.STATUS_ARCHIVED);
paneShouldBeOpen = true;
- spl.openPane();
+ showConversationsOverview();
xmppConnectionService.archiveConversation(conversation);
if (conversationList.size() > 0) {
setSelectedConversation(conversationList.get(0));
@@ -376,6 +434,7 @@ public class ConversationActivity extends XmppActivity implements
}
}
+ @SuppressLint("InflateParams")
protected void clearHistoryDialog(final Conversation conversation) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.clear_conversation_history));
@@ -390,7 +449,7 @@ public class ConversationActivity extends XmppActivity implements
@Override
public void onClick(DialogInterface dialog, int which) {
- activity.xmppConnectionService
+ ConversationActivity.this.xmppConnectionService
.clearConversationHistory(conversation);
if (endConversationCheckBox.isChecked()) {
endConversation(conversation);
@@ -399,7 +458,7 @@ public class ConversationActivity extends XmppActivity implements
});
builder.create().show();
}
-
+
protected void attachFileDialog() {
View menuAttachFile = findViewById(R.id.action_attach_file);
if (menuAttachFile == null) {
@@ -470,6 +529,8 @@ public class ConversationActivity extends XmppActivity implements
conversation.setNextEncryption(Message.ENCRYPTION_NONE);
break;
}
+ xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
fragment.updateChatMsgHint();
return true;
}
@@ -523,6 +584,8 @@ public class ConversationActivity extends XmppActivity implements
+ (durations[which] * 1000);
}
conversation.setMutedTill(till);
+ ConversationActivity.this.xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
.findFragmentByTag("conversation");
if (selectedFragment != null) {
@@ -550,8 +613,8 @@ public class ConversationActivity extends XmppActivity implements
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (!spl.isOpen()) {
- spl.openPane();
+ if (!isConversationsOverviewVisable()) {
+ showConversationsOverview();
return false;
}
}
@@ -599,62 +662,75 @@ public class ConversationActivity extends XmppActivity implements
xmppConnectionService.removeOnConversationListChangedListener();
xmppConnectionService.removeOnAccountListChangedListener();
xmppConnectionService.removeOnRosterUpdateListener();
+ xmppConnectionService.getNotificationService().setOpenConversation(
+ null);
}
super.onStop();
}
@Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ Conversation conversation = getSelectedConversation();
+ if (conversation != null) {
+ savedInstanceState.putString(STATE_OPEN_CONVERSATION,
+ conversation.getUuid());
+ }
+ savedInstanceState.putBoolean(STATE_PANEL_OPEN,
+ isConversationsOverviewVisable());
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ @Override
void onBackendConnected() {
this.registerListener();
- if (conversationList.size() == 0) {
- updateConversationList();
+ updateConversationList();
+
+ if (xmppConnectionService.getAccounts().size() == 0) {
+ startActivity(new Intent(this, EditAccountActivity.class));
+ } else if (conversationList.size() <= 0) {
+ startActivity(new Intent(this, StartConversationActivity.class));
+ finish();
+ } else if (mOpenConverstaion != null) {
+ selectConversationByUuid(mOpenConverstaion);
+ paneShouldBeOpen = mPanelOpen;
+ if (paneShouldBeOpen) {
+ showConversationsOverview();
+ }
+ swapConversationFragment();
+ mOpenConverstaion = null;
+ } else if (getIntent() != null
+ && VIEW_CONVERSATION.equals(getIntent().getType())) {
+ String uuid = (String) getIntent().getExtras().get(CONVERSATION);
+ String text = getIntent().getExtras().getString(TEXT, null);
+ selectConversationByUuid(uuid);
+ paneShouldBeOpen = false;
+ swapConversationFragment().setText(text);
+ setIntent(null);
+ } else {
+ showConversationsOverview();
+ ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
+ .findFragmentByTag("conversation");
+ if (selectedFragment != null) {
+ selectedFragment.onBackendConnected();
+ } else {
+ pendingImageUri = null;
+ setSelectedConversation(conversationList.get(0));
+ swapConversationFragment();
+ }
}
- if (getSelectedConversation() != null && pendingImageUri != null) {
+ if (pendingImageUri != null) {
attachImageToConversation(getSelectedConversation(),
pendingImageUri);
pendingImageUri = null;
- } else {
- pendingImageUri = null;
}
+ ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
+ }
- if ((getIntent().getAction() != null)
- && (getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
- if (getIntent().getType().equals(
- ConversationActivity.VIEW_CONVERSATION)) {
- handledViewIntent = true;
-
- String convToView = (String) getIntent().getExtras().get(
- CONVERSATION);
-
- for (int i = 0; i < conversationList.size(); ++i) {
- if (conversationList.get(i).getUuid().equals(convToView)) {
- setSelectedConversation(conversationList.get(i));
- }
- }
- paneShouldBeOpen = false;
- String text = getIntent().getExtras().getString(TEXT, null);
- swapConversationFragment().setText(text);
- }
- } else {
- if (xmppConnectionService.getAccounts().size() == 0) {
- startActivity(new Intent(this, EditAccountActivity.class));
- } else if (conversationList.size() <= 0) {
- // add no history
- startActivity(new Intent(this, StartConversationActivity.class));
- finish();
- } else {
- spl.openPane();
- // find currently loaded fragment
- ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
- .findFragmentByTag("conversation");
- if (selectedFragment != null) {
- selectedFragment.onBackendConnected();
- } else {
- setSelectedConversation(conversationList.get(0));
- swapConversationFragment();
- }
- ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
+ private void selectConversationByUuid(String uuid) {
+ for (int i = 0; i < conversationList.size(); ++i) {
+ if (conversationList.get(i).getUuid().equals(uuid)) {
+ setSelectedConversation(conversationList.get(i));
}
}
}
@@ -778,7 +854,7 @@ public class ConversationActivity extends XmppActivity implements
@Override
public void userInputRequried(PendingIntent pi,
Message message) {
- activity.runIntent(pi,
+ ConversationActivity.this.runIntent(pi,
ConversationActivity.REQUEST_SEND_MESSAGE);
}
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index feed9df5..cdaa7152 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -76,10 +76,11 @@ public class ConversationFragment extends Fragment {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
+ if (actionId == EditorInfo.IME_ACTION_SEND) {
InputMethodManager imm = (InputMethodManager) v.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ sendMessage();
return true;
} else {
return false;
@@ -131,6 +132,14 @@ public class ConversationFragment extends Fragment {
}
};
+ private OnClickListener joinMuc = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.xmppConnectionService.joinMuc(conversation);
+ }
+ };
+
private OnClickListener enterPassword = new OnClickListener() {
@Override
@@ -169,6 +178,7 @@ public class ConversationFragment extends Fragment {
conversation, timestamp);
messageList.clear();
messageList.addAll(conversation.getMessages());
+ updateStatusMessages();
messageListAdapter.notifyDataSetChanged();
if (size != 0) {
messagesLoaded = true;
@@ -244,9 +254,7 @@ public class ConversationFragment extends Fragment {
@Override
public void onClick(View v) {
- if (activity.getSlidingPaneLayout().isSlideable()) {
- activity.getSlidingPaneLayout().closePane();
- }
+ activity.hideConversationsOverview();
}
});
mEditMessage.setOnEditorActionListener(mEditorActionListener);
@@ -375,17 +383,10 @@ public class ConversationFragment extends Fragment {
int position = mEditMessage.length();
Editable etext = mEditMessage.getText();
Selection.setSelection(etext, position);
- if (activity.getSlidingPaneLayout().isSlideable()) {
+ if (activity.isConversationsOverviewHideable()) {
if (!activity.shouldPaneBeOpen()) {
- activity.getSlidingPaneLayout().closePane();
- activity.getActionBar().setDisplayHomeAsUpEnabled(true);
- activity.getActionBar().setHomeButtonEnabled(true);
- if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
- activity.getActionBar().setTitle(conversation.getName());
- } else {
- activity.getActionBar().setTitle(conversation.getContactJid().split("/")[0]);
- }
- activity.invalidateOptionsMenu();
+ activity.hideConversationsOverview();
+ activity.openConversation(conversation);
}
}
if (this.conversation.getMode() == Conversation.MODE_MULTI) {
@@ -437,6 +438,8 @@ public class ConversationFragment extends Fragment {
@Override
public void onClick(View v) {
conversation.setMutedTill(0);
+ activity.xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
updateMessages();
}
});
@@ -492,6 +495,18 @@ public class ConversationFragment extends Fragment {
showSnackbar(R.string.conference_requires_password,
R.string.enter_password, enterPassword);
break;
+ case MucOptions.ERROR_BANNED:
+ showSnackbar(R.string.conference_banned,
+ R.string.leave, leaveMuc);
+ break;
+ case MucOptions.ERROR_MEMBERS_ONLY:
+ showSnackbar(R.string.conference_members_only,
+ R.string.leave, leaveMuc);
+ break;
+ case MucOptions.KICKED_FROM_ROOM:
+ showSnackbar(R.string.conference_kicked, R.string.join,
+ joinMuc);
+ break;
default:
break;
}
@@ -500,9 +515,7 @@ public class ConversationFragment extends Fragment {
getActivity().invalidateOptionsMenu();
updateChatMsgHint();
if (!activity.shouldPaneBeOpen()) {
- activity.xmppConnectionService.markRead(conversation);
- UIHelper.updateNotification(getActivity(),
- activity.getConversationList(), null, false);
+ activity.xmppConnectionService.markRead(conversation, true);
activity.updateConversationList();
}
this.updateSendButton();
@@ -511,9 +524,7 @@ public class ConversationFragment extends Fragment {
private void messageSent() {
int size = this.messageList.size();
- if (size >= 1 && this.messagesView.getLastVisiblePosition() != size - 1) {
- messagesView.setSelection(size - 1);
- }
+ messagesView.setSelection(size - 1);
mEditMessage.setText("");
updateChatMsgHint();
}
@@ -667,6 +678,8 @@ public class ConversationFragment extends Fragment {
int which) {
conversation
.setNextEncryption(Message.ENCRYPTION_NONE);
+ xmppService.databaseBackend
+ .updateConversation(conversation);
message.setEncryption(Message.ENCRYPTION_NONE);
xmppService.sendMessage(message);
messageSent();
@@ -695,6 +708,8 @@ public class ConversationFragment extends Fragment {
conversation
.setNextEncryption(Message.ENCRYPTION_NONE);
message.setEncryption(Message.ENCRYPTION_NONE);
+ xmppService.databaseBackend
+ .updateConversation(conversation);
xmppService.sendMessage(message);
messageSent();
}
diff --git a/src/eu/siacs/conversations/ui/EditAccountActivity.java b/src/eu/siacs/conversations/ui/EditAccountActivity.java
index bc946115..0ec38547 100644
--- a/src/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -1,8 +1,12 @@
package eu.siacs.conversations.ui;
import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Intent;
import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AutoCompleteTextView;
@@ -10,9 +14,11 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
+import android.widget.Toast;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
@@ -38,6 +44,7 @@ public class EditAccountActivity extends XmppActivity {
private TextView mSessionEst;
private TextView mOtrFingerprint;
private TextView mOtrFingerprintHeadline;
+ private ImageButton mOtrFingerprintToClipboardButton;
private String jidToEdit;
private Account mAccount;
@@ -48,6 +55,12 @@ public class EditAccountActivity extends XmppActivity {
@Override
public void onClick(View v) {
+ if (mAccount != null
+ && mAccount.getStatus() == Account.STATUS_DISABLED) {
+ mAccount.setOption(Account.OPTION_DISABLED, false);
+ xmppConnectionService.updateAccount(mAccount);
+ return;
+ }
if (!Validator.isValidJid(mAccountJid.getText().toString())) {
mAccountJid.setError(getString(R.string.invalid_jid));
mAccountJid.requestFocus();
@@ -157,6 +170,25 @@ public class EditAccountActivity extends XmppActivity {
}
};
private KnownHostsAdapter mKnownHostsAdapter;
+ private TextWatcher mTextWatcher = new TextWatcher() {
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ updateSaveButton();
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ }
+ };
protected void finishInitialSetup(final Avatar avatar) {
runOnUiThread(new Runnable() {
@@ -197,6 +229,11 @@ public class EditAccountActivity extends XmppActivity {
this.mSaveButton.setEnabled(false);
this.mSaveButton.setTextColor(getSecondaryTextColor());
this.mSaveButton.setText(R.string.account_status_connecting);
+ } else if (mAccount != null
+ && mAccount.getStatus() == Account.STATUS_DISABLED) {
+ this.mSaveButton.setEnabled(true);
+ this.mSaveButton.setTextColor(getPrimaryTextColor());
+ this.mSaveButton.setText(R.string.enable);
} else {
this.mSaveButton.setEnabled(true);
this.mSaveButton.setTextColor(getPrimaryTextColor());
@@ -204,6 +241,10 @@ public class EditAccountActivity extends XmppActivity {
if (mAccount != null
&& mAccount.getStatus() == Account.STATUS_ONLINE) {
this.mSaveButton.setText(R.string.save);
+ if (!accountInfoEdited()) {
+ this.mSaveButton.setEnabled(false);
+ this.mSaveButton.setTextColor(getSecondaryTextColor());
+ }
} else {
this.mSaveButton.setText(R.string.connect);
}
@@ -213,12 +254,21 @@ public class EditAccountActivity extends XmppActivity {
}
}
+ protected boolean accountInfoEdited() {
+ return (!this.mAccount.getJid().equals(
+ this.mAccountJid.getText().toString()))
+ || (!this.mAccount.getPassword().equals(
+ this.mPassword.getText().toString()));
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_account);
this.mAccountJid = (AutoCompleteTextView) findViewById(R.id.account_jid);
+ this.mAccountJid.addTextChangedListener(this.mTextWatcher);
this.mPassword = (EditText) findViewById(R.id.account_password);
+ this.mPassword.addTextChangedListener(this.mTextWatcher);
this.mPasswordConfirm = (EditText) findViewById(R.id.account_password_confirm);
this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new);
this.mStats = (LinearLayout) findViewById(R.id.stats);
@@ -228,6 +278,7 @@ public class EditAccountActivity extends XmppActivity {
this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep);
this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint);
this.mOtrFingerprintHeadline = (TextView) findViewById(R.id.otr_fingerprint_headline);
+ this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard);
this.mSaveButton = (Button) findViewById(R.id.save_button);
this.mCancelButton = (Button) findViewById(R.id.cancel_button);
this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
@@ -255,7 +306,7 @@ public class EditAccountActivity extends XmppActivity {
this.jidToEdit = getIntent().getStringExtra("jid");
if (this.jidToEdit != null) {
this.mRegisterNew.setVisibility(View.GONE);
- getActionBar().setTitle(R.string.mgmt_account_edit);
+ getActionBar().setTitle(jidToEdit);
} else {
getActionBar().setTitle(R.string.action_add_account);
}
@@ -324,13 +375,30 @@ public class EditAccountActivity extends XmppActivity {
} else {
this.mServerInfoPep.setText(R.string.server_info_unavailable);
}
- String fingerprint = this.mAccount
+ final String fingerprint = this.mAccount
.getOtrFingerprint(xmppConnectionService);
if (fingerprint != null) {
this.mOtrFingerprintHeadline.setVisibility(View.VISIBLE);
this.mOtrFingerprint.setVisibility(View.VISIBLE);
this.mOtrFingerprint.setText(fingerprint);
+ this.mOtrFingerprintToClipboardButton
+ .setVisibility(View.VISIBLE);
+ this.mOtrFingerprintToClipboardButton
+ .setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+
+ if (OtrFingerprintToClipBoard(fingerprint)) {
+ Toast.makeText(
+ EditAccountActivity.this,
+ R.string.toast_message_otr_fingerprint,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
} else {
+ this.mOtrFingerprintToClipboardButton.setVisibility(View.GONE);
this.mOtrFingerprint.setVisibility(View.GONE);
this.mOtrFingerprintHeadline.setVisibility(View.GONE);
}
@@ -343,4 +411,15 @@ public class EditAccountActivity extends XmppActivity {
this.mStats.setVisibility(View.GONE);
}
}
+
+ private boolean OtrFingerprintToClipBoard(String fingerprint) {
+ ClipboardManager mClipBoardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ String label = getResources().getString(R.string.otr_fingerprint);
+ if (mClipBoardManager != null) {
+ ClipData mClipData = ClipData.newPlainText(label, fingerprint);
+ mClipBoardManager.setPrimaryClip(mClipData);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index ca17eb0d..afe9e06e 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -24,8 +24,6 @@ import android.widget.ListView;
public class ManageAccountActivity extends XmppActivity {
- protected ManageAccountActivity activity = this;
-
protected Account selectedAccount = null;
protected List<Account> accountList = new ArrayList<Account>();
@@ -72,7 +70,7 @@ public class ManageAccountActivity extends XmppActivity {
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
- activity.getMenuInflater().inflate(R.menu.manageaccounts_context, menu);
+ ManageAccountActivity.this.getMenuInflater().inflate(R.menu.manageaccounts_context, menu);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
this.selectedAccount = accountList.get(acmi.position);
if (this.selectedAccount.isOptionSet(Account.OPTION_DISABLED)) {
@@ -181,7 +179,7 @@ public class ManageAccountActivity extends XmppActivity {
}
private void publishOpenPGPPublicKey(Account account) {
- if (activity.hasPgp()) {
+ if (ManageAccountActivity.this.hasPgp()) {
announcePgp(account, null);
} else {
this.showInstallPgpDialog();
@@ -189,7 +187,7 @@ public class ManageAccountActivity extends XmppActivity {
}
private void deleteAccount(final Account account) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ AlertDialog.Builder builder = new AlertDialog.Builder(ManageAccountActivity.this);
builder.setTitle(getString(R.string.mgmt_account_are_you_sure));
builder.setIconAttribute(android.R.attr.alertDialogIcon);
builder.setMessage(getString(R.string.mgmt_account_delete_confirm_text));
diff --git a/src/eu/siacs/conversations/ui/SettingsActivity.java b/src/eu/siacs/conversations/ui/SettingsActivity.java
index fc361fb8..fc6308fc 100644
--- a/src/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/eu/siacs/conversations/ui/SettingsActivity.java
@@ -21,7 +21,7 @@ public class SettingsActivity extends XmppActivity implements
super.onCreate(savedInstanceState);
mSettingsFragment = new SettingsFragment();
getFragmentManager().beginTransaction()
- .replace(android.R.id.content,mSettingsFragment).commit();
+ .replace(android.R.id.content, mSettingsFragment).commit();
}
@Override
@@ -34,12 +34,16 @@ public class SettingsActivity extends XmppActivity implements
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
- ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource");
- if (resources!=null) {
- ArrayList<CharSequence> entries = new ArrayList<CharSequence>(Arrays.asList(resources.getEntries()));
- entries.add(0,Build.MODEL);
- resources.setEntries(entries.toArray(new CharSequence[entries.size()]));
- resources.setEntryValues(entries.toArray(new CharSequence[entries.size()]));
+ ListPreference resources = (ListPreference) mSettingsFragment
+ .findPreference("resource");
+ if (resources != null) {
+ ArrayList<CharSequence> entries = new ArrayList<CharSequence>(
+ Arrays.asList(resources.getEntries()));
+ entries.add(0, Build.MODEL);
+ resources.setEntries(entries.toArray(new CharSequence[entries
+ .size()]));
+ resources.setEntryValues(entries.toArray(new CharSequence[entries
+ .size()]));
}
}
diff --git a/src/eu/siacs/conversations/ui/StartConversationActivity.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java
index db6c1509..a1a2d4c2 100644
--- a/src/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -1,9 +1,12 @@
package eu.siacs.conversations.ui;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
@@ -14,6 +17,8 @@ import android.app.ListFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
@@ -157,6 +162,8 @@ public class StartConversationActivity extends XmppActivity {
});
}
};
+ private MenuItem mMenuSearchView;
+ private String mInitialJid;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -308,7 +315,8 @@ public class StartConversationActivity extends XmppActivity {
}
- protected void showCreateContactDialog() {
+ @SuppressLint("InflateParams")
+ protected void showCreateContactDialog(String prefilledJid) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.create_contact);
View dialogView = getLayoutInflater().inflate(
@@ -318,6 +326,9 @@ public class StartConversationActivity extends XmppActivity {
.findViewById(R.id.jid);
jid.setAdapter(new KnownHostsAdapter(this,
android.R.layout.simple_list_item_1, mKnownHosts));
+ if (prefilledJid != null) {
+ jid.append(prefilledJid);
+ }
populateAccountSpinner(spinner);
builder.setView(dialogView);
builder.setNegativeButton(R.string.cancel, null);
@@ -348,8 +359,8 @@ public class StartConversationActivity extends XmppActivity {
jid.setError(getString(R.string.contact_already_exists));
} else {
xmppConnectionService.createContact(contact);
- switchToConversation(contact);
dialog.dismiss();
+ switchToConversation(contact);
}
} else {
jid.setError(getString(R.string.invalid_jid));
@@ -359,6 +370,7 @@ public class StartConversationActivity extends XmppActivity {
}
+ @SuppressLint("InflateParams")
protected void showJoinConferenceDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.join_conference);
@@ -391,6 +403,10 @@ public class StartConversationActivity extends XmppActivity {
String conferenceJid = jid.getText().toString();
Account account = xmppConnectionService
.findAccountByJid(accountJid);
+ if (account == null) {
+ dialog.dismiss();
+ return;
+ }
if (bookmarkCheckBox.isChecked()) {
if (account.hasBookmarkFor(conferenceJid)) {
jid.setError(getString(R.string.bookmark_already_exists));
@@ -409,6 +425,7 @@ public class StartConversationActivity extends XmppActivity {
xmppConnectionService
.joinMuc(conversation);
}
+ dialog.dismiss();
switchToConversation(conversation);
}
} else {
@@ -418,6 +435,7 @@ public class StartConversationActivity extends XmppActivity {
if (!conversation.getMucOptions().online()) {
xmppConnectionService.joinMuc(conversation);
}
+ dialog.dismiss();
switchToConversation(conversation);
}
} else {
@@ -449,9 +467,9 @@ public class StartConversationActivity extends XmppActivity {
.findItem(R.id.action_create_contact);
MenuItem menuCreateConference = (MenuItem) menu
.findItem(R.id.action_join_conference);
- MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
- menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
- View mSearchView = menuSearchView.getActionView();
+ mMenuSearchView = (MenuItem) menu.findItem(R.id.action_search);
+ mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+ View mSearchView = mMenuSearchView.getActionView();
mSearchEditText = (EditText) mSearchView
.findViewById(R.id.search_field);
mSearchEditText.addTextChangedListener(mSearchTextWatcher);
@@ -460,6 +478,11 @@ public class StartConversationActivity extends XmppActivity {
} else {
menuCreateContact.setVisible(false);
}
+ if (mInitialJid != null) {
+ mMenuSearchView.expandActionView();
+ mSearchEditText.append(mInitialJid);
+ filter(mInitialJid);
+ }
return true;
}
@@ -467,7 +490,7 @@ public class StartConversationActivity extends XmppActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create_contact:
- showCreateContactDialog();
+ showCreateContactDialog(null);
break;
case R.id.action_join_conference:
showJoinConferenceDialog();
@@ -486,13 +509,8 @@ public class StartConversationActivity extends XmppActivity {
}
@Override
- void onBackendConnected() {
+ protected void onBackendConnected() {
xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate);
- if (mSearchEditText != null) {
- filter(mSearchEditText.getText().toString());
- } else {
- filter(null);
- }
this.mActivatedAccounts.clear();
for (Account account : xmppConnectionService.getAccounts()) {
if (account.getStatus() != Account.STATUS_DISABLED) {
@@ -502,6 +520,55 @@ public class StartConversationActivity extends XmppActivity {
this.mKnownHosts = xmppConnectionService.getKnownHosts();
this.mKnownConferenceHosts = xmppConnectionService
.getKnownConferenceHosts();
+ if (!startByIntent()) {
+ if (mSearchEditText != null) {
+ filter(mSearchEditText.getText().toString());
+ } else {
+ filter(null);
+ }
+ }
+ }
+
+ protected boolean startByIntent() {
+ if (getIntent() != null
+ && Intent.ACTION_SENDTO.equals(getIntent().getAction())) {
+ try {
+ String jid = URLDecoder.decode(
+ getIntent().getData().getEncodedPath(), "UTF-8").split(
+ "/")[1];
+ setIntent(null);
+ return handleJid(jid);
+ } catch (UnsupportedEncodingException e) {
+ setIntent(null);
+ return false;
+ }
+ } else if (getIntent() != null
+ && Intent.ACTION_VIEW.equals(getIntent().getAction())) {
+ Uri uri = getIntent().getData();
+ String jid = uri.getSchemeSpecificPart().split("\\?")[0];
+ return handleJid(jid);
+ }
+ return false;
+ }
+
+ private boolean handleJid(String jid) {
+ List<Contact> contacts = xmppConnectionService.findContacts(jid);
+ if (contacts.size() == 0) {
+ showCreateContactDialog(jid);
+ return false;
+ } else if (contacts.size() == 1) {
+ switchToConversation(contacts.get(0));
+ return true;
+ } else {
+ if (mMenuSearchView != null) {
+ mMenuSearchView.expandActionView();
+ mSearchEditText.setText(jid);
+ filter(jid);
+ } else {
+ mInitialJid = jid;
+ }
+ return true;
+ }
}
protected void filter(String needle) {
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 26a33d1a..cd77557c 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -15,6 +15,7 @@ import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
import eu.siacs.conversations.utils.ExceptionHelper;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
@@ -58,11 +59,12 @@ public abstract class XmppActivity extends Activity {
protected int mPrimaryTextColor;
protected int mSecondaryTextColor;
+ protected int mSecondaryBackgroundColor;
protected int mColorRed;
protected int mColorOrange;
protected int mColorGreen;
protected int mPrimaryColor;
-
+
protected boolean mUseSubject = true;
private DisplayMetrics metrics;
@@ -206,6 +208,8 @@ public abstract class XmppActivity extends Activity {
mColorOrange = getResources().getColor(R.color.orange);
mColorGreen = getResources().getColor(R.color.green);
mPrimaryColor = getResources().getColor(R.color.primary);
+ mSecondaryBackgroundColor = getResources().getColor(
+ R.color.secondarybackground);
if (getPreferences().getBoolean("use_larger_font", false)) {
setTheme(R.style.ConversationsTheme_LargerText);
}
@@ -216,7 +220,7 @@ public abstract class XmppActivity extends Activity {
return PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
}
-
+
public boolean useSubjectToIdentifyConference() {
return mUseSubject;
}
@@ -245,6 +249,7 @@ public abstract class XmppActivity extends Activity {
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
}
startActivity(viewConversationIntent);
+ finish();
}
public void switchToContactDetails(Contact contact) {
@@ -254,7 +259,7 @@ public abstract class XmppActivity extends Activity {
intent.putExtra("contact", contact.getJid());
startActivity(intent);
}
-
+
public void switchToAccount(Account account) {
Intent intent = new Intent(this, EditAccountActivity.class);
intent.putExtra("jid", account.getJid());
@@ -292,6 +297,8 @@ public abstract class XmppActivity extends Activity {
if (conversation != null) {
conversation
.setNextEncryption(Message.ENCRYPTION_PGP);
+ xmppConnectionService.databaseBackend
+ .updateConversation(conversation);
}
}
@@ -389,6 +396,7 @@ public abstract class XmppActivity extends Activity {
quickEdit(previousValue, callback, true);
}
+ @SuppressLint("InflateParams")
private void quickEdit(final String previousValue,
final OnValueEdited callback, boolean password) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -514,6 +522,10 @@ public abstract class XmppActivity extends Activity {
return this.mPrimaryColor;
}
+ public int getSecondaryBackgroundColor() {
+ return this.mSecondaryBackgroundColor;
+ }
+
class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Message message = null;
diff --git a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index e40723f4..f74856b0 100644
--- a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -40,9 +40,10 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
Conversation conv = getItem(position);
if (this.activity instanceof ConversationActivity) {
ConversationActivity activity = (ConversationActivity) this.activity;
- if (!activity.getSlidingPaneLayout().isSlideable()) {
+ if (!activity.isConversationsOverviewHideable()) {
if (conv == activity.getSelectedConversation()) {
- view.setBackgroundColor(0xffdddddd);
+ view.setBackgroundColor(activity
+ .getSecondaryBackgroundColor());
} else {
view.setBackgroundColor(Color.TRANSPARENT);
}
@@ -52,7 +53,8 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
}
TextView convName = (TextView) view
.findViewById(R.id.conversation_name);
- if (conv.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
+ if (conv.getMode() == Conversation.MODE_SINGLE
+ || activity.useSubjectToIdentifyConference()) {
convName.setText(conv.getName());
} else {
convName.setText(conv.getContactJid().split("/")[0]);
diff --git a/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
index 9ef427fc..df67e566 100644
--- a/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -24,7 +24,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ListItem item = getItem(position);
if (view == null) {
- view = (View) inflater.inflate(R.layout.contact, null);
+ view = (View) inflater.inflate(R.layout.contact, parent, false);
}
TextView name = (TextView) view.findViewById(R.id.contact_display_name);
TextView jid = (TextView) view.findViewById(R.id.contact_jid);
@@ -36,4 +36,4 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
return view;
}
-} \ No newline at end of file
+}
diff --git a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 035d18c5..2671cf50 100644
--- a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -417,7 +417,17 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder = (ViewHolder) view.getTag();
}
- if (type == STATUS || type == NULL) {
+ if (type == STATUS) {
+ return view;
+ }
+ if (type == NULL) {
+ if (position == getCount() - 1) {
+ view.getLayoutParams().height = 1;
+ } else {
+ view.getLayoutParams().height = 0;
+
+ }
+ view.setLayoutParams(view.getLayoutParams());
return view;
}
diff --git a/src/eu/siacs/conversations/utils/DNSHelper.java b/src/eu/siacs/conversations/utils/DNSHelper.java
index fd3b1953..c51a75ac 100644
--- a/src/eu/siacs/conversations/utils/DNSHelper.java
+++ b/src/eu/siacs/conversations/utils/DNSHelper.java
@@ -30,17 +30,17 @@ public class DNSHelper {
String dns[] = client.findDNS();
if (dns != null) {
- // we have a list of DNS servers, let's go
for (String dnsserver : dns) {
InetAddress ip = InetAddress.getByName(dnsserver);
Bundle b = queryDNS(host, ip);
if (b.containsKey("name")) {
return b;
+ } else if (b.containsKey("error")
+ && "nosrv".equals(b.getString("error", null))) {
+ return b;
}
}
}
-
- // fallback
return queryDNS(host, InetAddress.getByName("8.8.8.8"));
}
@@ -164,10 +164,8 @@ public class DNSHelper {
}
} catch (SocketTimeoutException e) {
- Log.d(Config.LOGTAG, "timeout during dns");
namePort.putString("error", "timeout");
} catch (Exception e) {
- Log.d(Config.LOGTAG, "unhandled exception in sub project");
namePort.putString("error", "unhandled");
}
return namePort;
diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java
index f6e66cdb..671e66d5 100644
--- a/src/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/eu/siacs/conversations/utils/UIHelper.java
@@ -7,16 +7,15 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
-import java.util.regex.Matcher;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions.User;
import eu.siacs.conversations.ui.ConversationActivity;
import eu.siacs.conversations.ui.ManageAccountActivity;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
@@ -26,7 +25,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -34,13 +32,11 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.net.Uri;
-import android.preference.PreferenceManager;
import android.provider.ContactsContract.Contacts;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
-import android.text.Html;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
@@ -330,177 +326,6 @@ public class UIHelper {
mNotificationManager.notify(1111, notification);
}
- private static Pattern generateNickHighlightPattern(String nick) {
- // We expect a word boundary, i.e. space or start of string, followed by
- // the
- // nick (matched in case-insensitive manner), followed by optional
- // punctuation (for example "bob: i disagree" or "how are you alice?"),
- // followed by another word boundary.
- return Pattern.compile("\\b" + nick + "\\p{Punct}?\\b",
- Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
- }
-
- public static void updateNotification(Context context,
- List<Conversation> conversations, Conversation currentCon,
- boolean notify) {
- NotificationManager mNotificationManager = (NotificationManager) context
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- SharedPreferences preferences = PreferenceManager
- .getDefaultSharedPreferences(context);
- boolean showNofifications = preferences.getBoolean("show_notification",
- true);
- boolean vibrate = preferences.getBoolean("vibrate_on_notification",
- true);
- boolean alwaysNotify = preferences.getBoolean(
- "notify_in_conversation_when_highlighted", false);
-
- if (!showNofifications) {
- mNotificationManager.cancel(2342);
- return;
- }
-
- String targetUuid = "";
-
- if ((currentCon != null)
- && (currentCon.getMode() == Conversation.MODE_MULTI)
- && (!alwaysNotify) && notify) {
- String nick = currentCon.getMucOptions().getActualNick();
- Pattern highlight = generateNickHighlightPattern(nick);
- Matcher m = highlight.matcher(currentCon.getLatestMessage()
- .getBody());
- notify = m.find()
- || (currentCon.getLatestMessage().getType() == Message.TYPE_PRIVATE);
- }
-
- List<Conversation> unread = new ArrayList<Conversation>();
- for (Conversation conversation : conversations) {
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- if ((!conversation.isRead())
- && ((wasHighlightedOrPrivate(conversation) || (alwaysNotify)))) {
- unread.add(conversation);
- }
- } else {
- if (!conversation.isRead()) {
- unread.add(conversation);
- }
- }
- }
- String ringtone = preferences.getString("notification_ringtone", null);
-
- NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
- context);
- if (unread.size() == 0) {
- mNotificationManager.cancel(2342);
- return;
- } else if (unread.size() == 1) {
- Conversation conversation = unread.get(0);
- targetUuid = conversation.getUuid();
- mBuilder.setLargeIcon(conversation.getImage(context, 64));
- mBuilder.setContentTitle(conversation.getName());
- if (notify) {
- mBuilder.setTicker(conversation.getLatestMessage()
- .getReadableBody(context));
- }
- StringBuilder bigText = new StringBuilder();
- List<Message> messages = conversation.getMessages();
- String firstLine = "";
- for (int i = messages.size() - 1; i >= 0; --i) {
- if (!messages.get(i).isRead()) {
- if (i == messages.size() - 1) {
- firstLine = messages.get(i).getReadableBody(context);
- bigText.append(firstLine);
- } else {
- firstLine = messages.get(i).getReadableBody(context);
- bigText.insert(0, firstLine + "\n");
- }
- } else {
- break;
- }
- }
- mBuilder.setContentText(firstLine);
- mBuilder.setStyle(new NotificationCompat.BigTextStyle()
- .bigText(bigText.toString()));
- } else {
- NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
- style.setBigContentTitle(unread.size() + " "
- + context.getString(R.string.unread_conversations));
- StringBuilder names = new StringBuilder();
- for (int i = 0; i < unread.size(); ++i) {
- targetUuid = unread.get(i).getUuid();
- if (i < unread.size() - 1) {
- names.append(unread.get(i).getName() + ", ");
- } else {
- names.append(unread.get(i).getName());
- }
- style.addLine(Html.fromHtml("<b>"
- + unread.get(i).getName()
- + "</b> "
- + unread.get(i).getLatestMessage()
- .getReadableBody(context)));
- }
- mBuilder.setContentTitle(unread.size() + " "
- + context.getString(R.string.unread_conversations));
- mBuilder.setContentText(names.toString());
- mBuilder.setStyle(style);
- }
- if ((currentCon != null) && (notify)) {
- targetUuid = currentCon.getUuid();
- }
- if (unread.size() != 0) {
- mBuilder.setSmallIcon(R.drawable.ic_notification);
- if (notify) {
- if (vibrate) {
- int dat = 70;
- long[] pattern = { 0, 3 * dat, dat, dat };
- mBuilder.setVibrate(pattern);
- }
- mBuilder.setLights(0xffffffff, 2000, 4000);
- if (ringtone != null) {
- mBuilder.setSound(Uri.parse(ringtone));
- }
- }
-
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
- stackBuilder.addParentStack(ConversationActivity.class);
-
- Intent viewConversationIntent = new Intent(context,
- ConversationActivity.class);
- viewConversationIntent.setAction(Intent.ACTION_VIEW);
- viewConversationIntent.putExtra(ConversationActivity.CONVERSATION,
- targetUuid);
- viewConversationIntent
- .setType(ConversationActivity.VIEW_CONVERSATION);
-
- stackBuilder.addNextIntent(viewConversationIntent);
-
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
- 0, PendingIntent.FLAG_UPDATE_CURRENT);
-
- mBuilder.setContentIntent(resultPendingIntent);
- Notification notification = mBuilder.build();
- mNotificationManager.notify(2342, notification);
- }
- }
-
- private static boolean wasHighlightedOrPrivate(Conversation conversation) {
- List<Message> messages = conversation.getMessages();
- String nick = conversation.getMucOptions().getActualNick();
- Pattern highlight = generateNickHighlightPattern(nick);
- for (int i = messages.size() - 1; i >= 0; --i) {
- if (messages.get(i).isRead()) {
- break;
- } else {
- Matcher m = highlight.matcher(messages.get(i).getBody());
- if (m.find()
- || messages.get(i).getType() == Message.TYPE_PRIVATE) {
- return true;
- }
- }
- }
- return false;
- }
-
public static void prepareContactBadge(final Activity activity,
QuickContactBadge badge, final Contact contact, Context context) {
if (contact.getSystemAccount() != null) {
@@ -511,6 +336,7 @@ public class UIHelper {
badge.setImageBitmap(contact.getImage(72, context));
}
+ @SuppressLint("InflateParams")
public static AlertDialog getVerifyFingerprintDialog(
final ConversationActivity activity,
final Conversation conversation, final View msg) {
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index 8694e68c..54409be4 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -166,8 +166,14 @@ public class XmppConnection implements Runnable {
+ ":" + srvRecordPort);
socket = new Socket(srvRecordServer, srvRecordPort);
}
- } else {
+ } else if (namePort.containsKey("error")
+ && "nosrv".equals(namePort.getString("error", null))) {
socket = new Socket(account.getServer(), 5222);
+ } else {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": timeout in DNS resolution");
+ changeStatus(Account.STATUS_OFFLINE);
+ return;
}
OutputStream out = socket.getOutputStream();
tagWriter.setOutputStream(out);
@@ -307,7 +313,8 @@ public class XmppConnection implements Runnable {
} catch (NumberFormatException e) {
}
- changeStatus(Account.STATUS_ONLINE);
+ sendInitialPing();
+
} else if (nextTag.isStart("r")) {
tagReader.readElement(nextTag);
AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
@@ -348,6 +355,22 @@ public class XmppConnection implements Runnable {
}
}
+ private void sendInitialPing() {
+ Log.d(Config.LOGTAG, account.getJid() + ": sending intial ping");
+ IqPacket iq = new IqPacket(IqPacket.TYPE_GET);
+ iq.setFrom(account.getFullJid());
+ iq.addChild("ping", "urn:xmpp:ping");
+ this.sendIqPacket(iq, new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Log.d(Config.LOGTAG, account.getJid()
+ + ": online with resource " + account.getResource());
+ changeStatus(Account.STATUS_ONLINE);
+ }
+ });
+ }
+
private Element processPacket(Tag currentTag, int packetType)
throws XmlPullParserException, IOException {
Element element;
@@ -372,8 +395,11 @@ public class XmppConnection implements Runnable {
while (!nextTag.isEnd(element.getName())) {
if (!nextTag.isNo()) {
Element child = tagReader.readElement(nextTag);
- if ((packetType == PACKET_IQ)
- && ("jingle".equals(child.getName()))) {
+ String type = currentTag.getAttribute("type");
+ if (packetType == PACKET_IQ
+ && "jingle".equals(child.getName())
+ && ("set".equalsIgnoreCase(type) || "get"
+ .equalsIgnoreCase(type))) {
element = new JinglePacket();
element.setAttributes(currentTag.getAttributes());
}
@@ -410,7 +436,9 @@ public class XmppConnection implements Runnable {
}
packetCallbacks.remove(packet.getId());
- } else if (this.unregisteredIqListener != null) {
+ } else if ((packet.getType() == IqPacket.TYPE_GET || packet
+ .getType() == IqPacket.TYPE_SET)
+ && this.unregisteredIqListener != null) {
this.unregisteredIqListener.onIqPacketReceived(account, packet);
}
}
@@ -657,7 +685,7 @@ public class XmppConnection implements Runnable {
if (bind != null) {
Element jid = bind.findChild("jid");
if (jid != null && jid.getContent() != null) {
- account.setResource(jid.getContent().split("/",2)[1]);
+ account.setResource(jid.getContent().split("/", 2)[1]);
if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) {
smVersion = 3;
EnablePacket enable = new EnablePacket(smVersion);
@@ -677,7 +705,7 @@ public class XmppConnection implements Runnable {
if (bindListener != null) {
bindListener.onBind(account);
}
- changeStatus(Account.STATUS_ONLINE);
+ sendInitialPing();
} else {
disconnect(true);
}
@@ -882,8 +910,7 @@ public class XmppConnection implements Runnable {
}
public void disconnect(boolean force) {
- changeStatus(Account.STATUS_OFFLINE);
- Log.d(Config.LOGTAG, "disconnecting");
+ Log.d(Config.LOGTAG, account.getJid()+": disconnecting");
try {
if (force) {
socket.close();
@@ -901,6 +928,7 @@ public class XmppConnection implements Runnable {
Thread.sleep(100);
}
tagWriter.writeTag(Tag.end("stream:stream"));
+ socket.close();
} catch (IOException e) {
Log.d(Config.LOGTAG,
"io exception during disconnect");
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 4eac99e6..92fdbe0b 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -88,8 +88,8 @@ public class JingleConnection implements Downloadable {
sendSuccess();
if (acceptedAutomatically) {
message.markUnread();
- JingleConnection.this.mXmppConnectionService.notifyUi(
- message.getConversation(), true);
+ JingleConnection.this.mXmppConnectionService
+ .getNotificationService().push(message);
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
@@ -256,12 +256,12 @@ public class JingleConnection implements Downloadable {
this.status = STATUS_INITIATED;
Conversation conversation = this.mXmppConnectionService
.findOrCreateConversation(account,
- packet.getFrom().split("/",2)[0], false);
+ packet.getFrom().split("/", 2)[0], false);
this.message = new Message(conversation, "", Message.ENCRYPTION_NONE);
this.message.setType(Message.TYPE_IMAGE);
this.message.setStatus(Message.STATUS_RECEIVED_OFFER);
this.message.setDownloadable(this);
- String[] fromParts = packet.getFrom().split("/",2);
+ String[] fromParts = packet.getFrom().split("/", 2);
this.message.setPresence(fromParts[1]);
this.account = account;
this.initiator = packet.getFrom();
@@ -319,8 +319,8 @@ public class JingleConnection implements Downloadable {
+ " allowed size:"
+ this.mJingleConnectionManager
.getAutoAcceptFileSize());
- this.mXmppConnectionService
- .notifyUi(conversation, true);
+ this.mXmppConnectionService.getNotificationService()
+ .push(message);
}
this.file = this.mXmppConnectionService.getFileBackend()
.getJingleFile(message, false);