aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu/siacs
diff options
context:
space:
mode:
Diffstat (limited to 'src/eu/siacs')
-rw-r--r--src/eu/siacs/conversations/crypto/PgpEngine.java3
-rw-r--r--src/eu/siacs/conversations/entities/AbstractEntity.java5
-rw-r--r--src/eu/siacs/conversations/entities/Account.java30
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java131
-rw-r--r--src/eu/siacs/conversations/entities/Contact.java61
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java51
-rw-r--r--src/eu/siacs/conversations/entities/ListItem.java10
-rw-r--r--src/eu/siacs/conversations/entities/Message.java2
-rw-r--r--src/eu/siacs/conversations/entities/MucOptions.java58
-rw-r--r--src/eu/siacs/conversations/entities/Roster.java3
-rw-r--r--src/eu/siacs/conversations/generator/MessageGenerator.java24
-rw-r--r--src/eu/siacs/conversations/generator/PresenceGenerator.java43
-rw-r--r--src/eu/siacs/conversations/parser/AbstractParser.java15
-rw-r--r--src/eu/siacs/conversations/parser/IqParser.java90
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java190
-rw-r--r--src/eu/siacs/conversations/parser/PresenceParser.java50
-rw-r--r--src/eu/siacs/conversations/persistance/DatabaseBackend.java4
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java804
-rw-r--r--src/eu/siacs/conversations/ui/ChooseContactActivity.java140
-rw-r--r--src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java268
-rw-r--r--src/eu/siacs/conversations/ui/ContactDetailsActivity.java224
-rw-r--r--src/eu/siacs/conversations/ui/ContactsActivity.java598
-rw-r--r--src/eu/siacs/conversations/ui/ConversationActivity.java85
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java144
-rw-r--r--src/eu/siacs/conversations/ui/EditAccountDialog.java (renamed from src/eu/siacs/conversations/ui/EditAccount.java)25
-rw-r--r--src/eu/siacs/conversations/ui/ManageAccountActivity.java566
-rw-r--r--src/eu/siacs/conversations/ui/MucDetailsActivity.java213
-rw-r--r--src/eu/siacs/conversations/ui/OnAccountListChangedListener.java5
-rw-r--r--src/eu/siacs/conversations/ui/OnConversationListChangedListener.java5
-rw-r--r--src/eu/siacs/conversations/ui/OnPresenceSelected.java5
-rw-r--r--src/eu/siacs/conversations/ui/ShareWithActivity.java4
-rw-r--r--src/eu/siacs/conversations/ui/StartConversationActivity.java584
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java73
-rw-r--r--src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java69
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java39
-rw-r--r--src/eu/siacs/conversations/utils/UIHelper.java21
-rw-r--r--src/eu/siacs/conversations/xml/XmlReader.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java23
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java28
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java8
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java1
41 files changed, 2754 insertions, 1950 deletions
diff --git a/src/eu/siacs/conversations/crypto/PgpEngine.java b/src/eu/siacs/conversations/crypto/PgpEngine.java
index c0d8ca07..2d0c56e1 100644
--- a/src/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/eu/siacs/conversations/crypto/PgpEngine.java
@@ -98,8 +98,7 @@ public class PgpEngine {
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
PgpEngine.this.mXmppConnectionService
.updateMessage(message);
- PgpEngine.this.mXmppConnectionService.updateUi(
- message.getConversation(), false);
+ PgpEngine.this.mXmppConnectionService.updateConversationUi();
callback.success(message);
return;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
diff --git a/src/eu/siacs/conversations/entities/AbstractEntity.java b/src/eu/siacs/conversations/entities/AbstractEntity.java
index 0297fa66..4891723e 100644
--- a/src/eu/siacs/conversations/entities/AbstractEntity.java
+++ b/src/eu/siacs/conversations/entities/AbstractEntity.java
@@ -1,12 +1,9 @@
package eu.siacs.conversations.entities;
-import java.io.Serializable;
-
import android.content.ContentValues;
-public abstract class AbstractEntity implements Serializable {
+public abstract class AbstractEntity {
- private static final long serialVersionUID = -1895605706690653719L;
public static final String UUID = "uuid";
diff --git a/src/eu/siacs/conversations/entities/Account.java b/src/eu/siacs/conversations/entities/Account.java
index b9c87eac..0910516c 100644
--- a/src/eu/siacs/conversations/entities/Account.java
+++ b/src/eu/siacs/conversations/entities/Account.java
@@ -1,6 +1,10 @@
package eu.siacs.conversations.entities;
import java.security.interfaces.DSAPublicKey;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CopyOnWriteArrayList;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
@@ -15,8 +19,6 @@ import android.content.Context;
import android.database.Cursor;
public class Account extends AbstractEntity{
-
- private static final long serialVersionUID = 6174825093869578035L;
public static final String TABLENAME = "accounts";
@@ -66,6 +68,11 @@ public class Account extends AbstractEntity{
private String otrFingerprint;
private Roster roster = null;
+
+ private List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+
+ public List<Conversation> pendingConferenceJoins = new CopyOnWriteArrayList<Conversation>();
+ public List<Conversation> pendingConferenceLeaves = new CopyOnWriteArrayList<Conversation>();
public Account() {
this.uuid = "0";
@@ -149,7 +156,7 @@ public class Account extends AbstractEntity{
}
public String getJid() {
- return username+"@"+server;
+ return username.toLowerCase(Locale.getDefault())+"@"+server.toLowerCase(Locale.getDefault());
}
public JSONObject getKeys() {
@@ -296,4 +303,21 @@ public class Account extends AbstractEntity{
}
return this.roster;
}
+
+ public void setBookmarks(List<Bookmark> bookmarks) {
+ this.bookmarks = bookmarks;
+ }
+
+ public List<Bookmark> getBookmarks() {
+ return this.bookmarks;
+ }
+
+ public boolean hasBookmarkFor(String conferenceJid) {
+ for(Bookmark bmark : this.bookmarks) {
+ if (bmark.getJid().equals(conferenceJid)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
new file mode 100644
index 00000000..38c03410
--- /dev/null
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -0,0 +1,131 @@
+package eu.siacs.conversations.entities;
+
+import java.util.Locale;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xml.Element;
+
+public class Bookmark implements ListItem {
+
+ private Account account;
+ private String jid;
+ private String nick;
+ private String name;
+ private boolean autojoin;
+ private Conversation mJoinedConversation;
+
+ public Bookmark(Account account, String jid) {
+ 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());
+ }
+ return bookmark;
+ }
+
+ public void setAutojoin(boolean autojoin) {
+ this.autojoin = autojoin;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setNick(String nick) {
+ this.nick = nick;
+ }
+
+ @Override
+ public int compareTo(ListItem another) {
+ return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+ }
+
+ @Override
+ public String getDisplayName() {
+ if (this.mJoinedConversation!=null && (this.mJoinedConversation.getMucOptions().getSubject() != null)) {
+ return this.mJoinedConversation.getMucOptions().getSubject();
+ } else if (name!=null) {
+ return name;
+ } else {
+ return this.jid.split("@")[0];
+ }
+ }
+
+ @Override
+ public String getJid() {
+ return this.jid.toLowerCase(Locale.US);
+ }
+
+ public String getNick() {
+ return this.nick;
+ }
+
+ public boolean autojoin() {
+ return autojoin;
+ }
+
+ public boolean match(String needle) {
+ return needle == null
+ || getJid().contains(needle.toLowerCase(Locale.US))
+ || getDisplayName().toLowerCase(Locale.US)
+ .contains(needle.toLowerCase(Locale.US));
+ }
+
+ public Account getAccount() {
+ return this.account;
+ }
+
+ @Override
+ public Bitmap getImage(int dpSize, Context context) {
+ if (this.mJoinedConversation==null) {
+ return UIHelper.getContactPicture(getDisplayName(), dpSize, context, false);
+ } else {
+ return UIHelper.getContactPicture(this.mJoinedConversation, dpSize, context, false);
+ }
+ }
+
+ public void setConversation(Conversation conversation) {
+ this.mJoinedConversation = conversation;
+ }
+
+ 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);
+ }
+ return element;
+ }
+
+ public void unregisterConversation() {
+ if (this.mJoinedConversation != null) {
+ this.mJoinedConversation.deregisterWithBookmark();
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java
index a0047cdf..8f8e38a5 100644
--- a/src/eu/siacs/conversations/entities/Contact.java
+++ b/src/eu/siacs/conversations/entities/Contact.java
@@ -1,17 +1,21 @@
package eu.siacs.conversations.entities;
import java.util.HashSet;
+import java.util.Locale;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
import android.content.ContentValues;
+import android.content.Context;
import android.database.Cursor;
+import android.graphics.Bitmap;
-public class Contact {
+public class Contact implements ListItem {
public static final String TABLENAME = "contacts";
public static final String SYSTEMNAME = "systemname";
@@ -36,7 +40,7 @@ public class Contact {
protected Account account;
protected boolean inRoster = true;
-
+
public Lastseen lastseen = new Lastseen();
public Contact(String account, String systemName, String serverName,
@@ -78,12 +82,14 @@ public class Contact {
}
public String getJid() {
- return this.jid;
+ return this.jid.toLowerCase(Locale.getDefault());
}
public boolean match(String needle) {
- return (jid.toLowerCase().contains(needle.toLowerCase()) || (getDisplayName()
- .toLowerCase().contains(needle.toLowerCase())));
+ return needle == null
+ || jid.contains(needle.toLowerCase())
+ || getDisplayName().toLowerCase()
+ .contains(needle.toLowerCase());
}
public ContentValues getContentValues() {
@@ -126,27 +132,7 @@ public class Contact {
public Account getAccount() {
return this.account;
}
-
- public boolean couldBeMuc() {
- String[] split = this.getJid().split("@");
- if (split.length != 2) {
- return false;
- } else {
- String[] domainParts = split[1].split("\\.");
- if (domainParts.length < 3) {
- return false;
- } else {
- return (domainParts[0].equals("conf")
- || domainParts[0].equals("conference")
- || domainParts[0].equals("room")
- || domainParts[0].equals("muc")
- || domainParts[0].equals("chat")
- || domainParts[0].equals("sala")
- || domainParts[0].equals("salas"));
- }
- }
- }
-
+
public Presences getPresences() {
return this.presences;
}
@@ -269,9 +255,11 @@ public class Contact {
} else if (subscription.equals("from")) {
this.resetOption(Contact.Options.TO);
this.setOption(Contact.Options.FROM);
+ this.resetOption(Contact.Options.PREEMPTIVE_GRANT);
} else if (subscription.equals("both")) {
this.setOption(Contact.Options.TO);
this.setOption(Contact.Options.FROM);
+ this.resetOption(Contact.Options.PREEMPTIVE_GRANT);
} else if (subscription.equals("none")) {
this.resetOption(Contact.Options.FROM);
this.resetOption(Contact.Options.TO);
@@ -307,9 +295,28 @@ public class Contact {
public static final int DIRTY_PUSH = 6;
public static final int DIRTY_DELETE = 7;
}
-
+
public class Lastseen {
public long time = 0;
public String presence = null;
}
+
+ @Override
+ public int compareTo(ListItem another) {
+ return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+ }
+
+ public String getServer() {
+ String[] split = getJid().split("@");
+ if (split.length >= 2) {
+ return split[1];
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Bitmap getImage(int dpSize, Context context) {
+ return UIHelper.getContactPicture(this, dpSize, context, false);
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index c207a5c9..e04d7bf8 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -4,8 +4,6 @@ import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
import java.util.List;
-import eu.siacs.conversations.services.XmppConnectionService;
-
import net.java.otr4j.OtrException;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
import net.java.otr4j.crypto.OtrCryptoException;
@@ -18,9 +16,6 @@ import android.database.Cursor;
import android.net.Uri;
public class Conversation extends AbstractEntity {
-
- private static final long serialVersionUID = -6727528868973996739L;
-
public static final String TABLENAME = "conversations";
public static final int STATUS_AVAILABLE = 0;
@@ -66,6 +61,8 @@ public class Conversation extends AbstractEntity {
private boolean otrSessionNeedsStarting = false;
+ private Bookmark bookmark;
+
public Conversation(String name, Account account, String contactJid,
int mode) {
this(java.util.UUID.randomUUID().toString(), name, null, account
@@ -118,13 +115,10 @@ public class Conversation extends AbstractEntity {
}
}
- public void markRead(XmppConnectionService service) {
- markRead();
- if (service.confirmMessages() && this.latestMarkableMessageId != null) {
- service.sendConfirmMessage(getAccount(), getContactJid(),
- this.latestMarkableMessageId);
- this.latestMarkableMessageId = null;
- }
+ public String popLatestMarkableMessageId() {
+ String id = this.latestMarkableMessageId;
+ this.latestMarkableMessageId = null;
+ return id;
}
public Message getLatestMessage() {
@@ -147,6 +141,9 @@ public class Conversation extends AbstractEntity {
if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null)
&& useSubject) {
return getMucOptions().getSubject();
+ } else if (getMode() == MODE_MULTI && bookmark != null
+ && bookmark.getName() != null) {
+ return bookmark.getName();
} else {
return this.getContact().getDisplayName();
}
@@ -242,7 +239,7 @@ public class Conversation extends AbstractEntity {
this.otrSessionNeedsStarting = false;
return this.otrSession;
} else {
- this.otrSessionNeedsStarting = true;
+ this.otrSessionNeedsStarting = true;
}
return this.otrSession;
} catch (OtrException e) {
@@ -271,7 +268,7 @@ public class Conversation extends AbstractEntity {
}
}
}
-
+
public void endOtrIfNeeded() {
if (this.otrSession != null) {
if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
@@ -376,8 +373,32 @@ public class Conversation extends AbstractEntity {
public void setSymmetricKey(byte[] key) {
this.symmetricKey = key;
}
-
+
public byte[] getSymmetricKey() {
return this.symmetricKey;
}
+
+ public void setBookmark(Bookmark bookmark) {
+ this.bookmark = bookmark;
+ this.bookmark.setConversation(this);
+ }
+
+ public void deregisterWithBookmark() {
+ if (this.bookmark != null) {
+ this.bookmark.setConversation(null);
+ }
+ }
+
+ public Bookmark getBookmark() {
+ return this.bookmark;
+ }
+
+ public void failWaitingOtrMessages() {
+ for (Message message : this.messages) {
+ if (message.getEncryption() == Message.ENCRYPTION_OTR
+ && message.getStatus() == Message.STATUS_WAITING) {
+ message.setStatus(Message.STATUS_SEND_FAILED);
+ }
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/ListItem.java b/src/eu/siacs/conversations/entities/ListItem.java
new file mode 100644
index 00000000..c89c85d9
--- /dev/null
+++ b/src/eu/siacs/conversations/entities/ListItem.java
@@ -0,0 +1,10 @@
+package eu.siacs.conversations.entities;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+public interface ListItem extends Comparable<ListItem> {
+ public String getDisplayName();
+ public String getJid();
+ public Bitmap getImage(int dpSize, Context context);
+}
diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java
index 8e669c65..49c5ce58 100644
--- a/src/eu/siacs/conversations/entities/Message.java
+++ b/src/eu/siacs/conversations/entities/Message.java
@@ -7,8 +7,6 @@ import android.content.Context;
import android.database.Cursor;
public class Message extends AbstractEntity {
-
- private static final long serialVersionUID = 7222081895167103025L;
public static final String TABLENAME = "messages";
diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java
index 0f8e3565..0bb9b295 100644
--- a/src/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/eu/siacs/conversations/entities/MucOptions.java
@@ -10,7 +10,9 @@ import android.annotation.SuppressLint;
@SuppressLint("DefaultLocale")
public class MucOptions {
+ public static final int ERROR_NO_ERROR = 0;
public static final int ERROR_NICK_IN_USE = 1;
+ public static final int ERROR_ROOM_NOT_FOUND = 2;
public interface OnRenameListener {
public void onRename(boolean success);
@@ -82,11 +84,12 @@ public class MucOptions {
private ArrayList<User> users = new ArrayList<User>();
private Conversation conversation;
private boolean isOnline = false;
- private int error = 0;
+ private int error = ERROR_ROOM_NOT_FOUND;
private OnRenameListener renameListener = null;
private boolean aboutToRename = false;
private User self = new User();
private String subject = null;
+ private String joinnick;
public MucOptions(Account account) {
this.account = account;
@@ -123,10 +126,16 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role"));
user.setName(name);
- if (name.equals(getNick())) {
+ if (name.equals(this.joinnick)) {
this.isOnline = true;
- this.error = 0;
+ this.error = ERROR_NO_ERROR;
self = user;
+ if (aboutToRename) {
+ if (renameListener!=null) {
+ renameListener.onRename(true);
+ }
+ aboutToRename = false;
+ }
} else {
addUser(user);
}
@@ -145,17 +154,6 @@ public class MucOptions {
}
}
} else if (type.equals("unavailable")) {
- if (name.equals(getNick())) {
- Element item = packet.findChild("x","http://jabber.org/protocol/muc#user").findChild("item");
- String nick = item.getAttribute("nick");
- if (nick!=null) {
- aboutToRename = false;
- if (renameListener!=null) {
- renameListener.onRename(true);
- }
- this.setNick(nick);
- }
- }
deleteUser(packet.getAttribute("from").split("/")[1]);
} else if (type.equals("error")) {
Element error = packet.findChild("error");
@@ -165,6 +163,7 @@ public class MucOptions {
renameListener.onRename(false);
}
aboutToRename = false;
+ this.setJoinNick(getActualNick());
} else {
this.error = ERROR_NICK_IN_USE;
}
@@ -177,22 +176,29 @@ public class MucOptions {
return this.users;
}
- public String getNick() {
- String[] split = conversation.getContactJid().split("/");
- if (split.length == 2) {
- return split[1];
+ public String getProposedNick() {
+ String[] mucParts = conversation.getContactJid().split("/");
+ if (conversation.getBookmark() != null && conversation.getBookmark().getNick() != null) {
+ return conversation.getBookmark().getNick();
} else {
- if (conversation.getAccount()!=null) {
- return conversation.getAccount().getUsername();
+ if (mucParts.length == 2) {
+ return mucParts[1];
} else {
- return null;
+ return account.getUsername();
}
}
}
- public void setNick(String nick) {
- String jid = conversation.getContactJid().split("/")[0]+"/"+nick;
- conversation.setContactJid(jid);
+ public String getActualNick() {
+ if (this.self.getName()!=null) {
+ return this.self.getName();
+ } else {
+ return this.getProposedNick();
+ }
+ }
+
+ public void setJoinNick(String nick) {
+ this.joinnick = nick;
}
public void setConversation(Conversation conversation) {
@@ -268,4 +274,8 @@ public class MucOptions {
}
return true;
}
+
+ public String getJoinJid() {
+ return this.conversation.getContactJid().split("/")[0]+"/"+this.joinnick;
+ }
} \ 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 c1e40dbc..aa328664 100644
--- a/src/eu/siacs/conversations/entities/Roster.java
+++ b/src/eu/siacs/conversations/entities/Roster.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.entities;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
public class Roster {
@@ -19,7 +20,7 @@ public class Roster {
}
public Contact getContact(String jid) {
- String cleanJid = jid.split("/")[0];
+ String cleanJid = jid.split("/")[0].toLowerCase(Locale.getDefault());
if (contacts.containsKey(cleanJid)) {
return contacts.get(cleanJid);
} else {
diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java
index 28504b21..5a216a7e 100644
--- a/src/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/eu/siacs/conversations/generator/MessageGenerator.java
@@ -42,7 +42,7 @@ public class MessageGenerator {
delay.setAttribute("stamp", mDateFormat.format(date));
}
- public MessagePacket generateOtrChat(Message message) throws OtrException {
+ public MessagePacket generateOtrChat(Message message) {
return generateOtrChat(message, false);
}
@@ -106,4 +106,26 @@ public class MessageGenerator {
packet.setType(MessagePacket.TYPE_ERROR);
return packet;
}
+
+ public MessagePacket confirm(Account account, String to, String id) {
+ MessagePacket packet = new MessagePacket();
+ packet.setType(MessagePacket.TYPE_NORMAL);
+ packet.setTo(to);
+ packet.setFrom(account.getFullJid());
+ Element received = packet.addChild("displayed",
+ "urn:xmpp:chat-markers:0");
+ received.setAttribute("id", id);
+ return packet;
+ }
+
+ public MessagePacket conferenceSubject(Conversation conversation,String subject) {
+ MessagePacket packet = new MessagePacket();
+ packet.setType(MessagePacket.TYPE_GROUPCHAT);
+ packet.setTo(conversation.getContactJid().split("/")[0]);
+ Element subjectChild = new Element("subject");
+ subjectChild.setContent(subject);
+ packet.addChild(subjectChild);
+ packet.setFrom(conversation.getAccount().getJid());
+ return packet;
+ }
}
diff --git a/src/eu/siacs/conversations/generator/PresenceGenerator.java b/src/eu/siacs/conversations/generator/PresenceGenerator.java
new file mode 100644
index 00000000..a301392e
--- /dev/null
+++ b/src/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -0,0 +1,43 @@
+package eu.siacs.conversations.generator;
+
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
+
+public class PresenceGenerator {
+
+ private PresencePacket subscription(String type, Contact contact) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("type", type);
+ packet.setAttribute("to", contact.getJid());
+ packet.setAttribute("from", contact.getAccount().getJid());
+ return packet;
+ }
+
+ public PresencePacket requestPresenceUpdatesFrom(Contact contact) {
+ return subscription("subscribe", contact);
+ }
+
+ public PresencePacket stopPresenceUpdatesFrom(Contact contact) {
+ return subscription("unsubscribe", contact);
+ }
+
+ public PresencePacket stopPresenceUpdatesTo(Contact contact) {
+ return subscription("unsubscribed", contact);
+ }
+
+ public PresencePacket sendPresenceUpdatesTo(Contact contact) {
+ return subscription("subscribed", contact);
+ }
+
+ public PresencePacket sendPresence(Account account) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("from", account.getFullJid());
+ String sig = account.getPgpSignature();
+ if (sig != null) {
+ packet.addChild("status").setContent("online");
+ packet.addChild("x", "jabber:x:signed").setContent(sig);
+ }
+ return packet;
+ }
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java
index f9a7b1c0..c4c6720a 100644
--- a/src/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/eu/siacs/conversations/parser/AbstractParser.java
@@ -2,6 +2,8 @@ package eu.siacs.conversations.parser;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.Locale;
@@ -20,11 +22,16 @@ public abstract class AbstractParser {
protected long getTimestamp(Element packet) {
long now = System.currentTimeMillis();
- if (packet.hasChild("delay")) {
+ ArrayList<String> stamps = new ArrayList<String>();
+ for(Element child : packet.getChildren()) {
+ if (child.getName().equals("delay")) {
+ stamps.add(child.getAttribute("stamp").replace("Z", "+0000"));
+ }
+ }
+ Collections.sort(stamps);
+ if (stamps.size() >= 1) {
try {
- String stamp = packet.findChild("delay").getAttribute(
- "stamp");
- stamp = stamp.replace("Z", "+0000");
+ String stamp = stamps.get(stamps.size() - 1);
if (stamp.contains(".")) {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",Locale.US)
.parse(stamp);
diff --git a/src/eu/siacs/conversations/parser/IqParser.java b/src/eu/siacs/conversations/parser/IqParser.java
new file mode 100644
index 00000000..049d37e1
--- /dev/null
+++ b/src/eu/siacs/conversations/parser/IqParser.java
@@ -0,0 +1,90 @@
+package eu.siacs.conversations.parser;
+
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnIqPacketReceived;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
+public class IqParser extends AbstractParser implements OnIqPacketReceived {
+
+ public IqParser(XmppConnectionService service) {
+ super(service);
+ }
+
+ public void rosterItems(Account account, Element query) {
+ String version = query.getAttribute("ver");
+ if (version != null) {
+ account.getRoster().setVersion(version);
+ }
+ for (Element item : query.getChildren()) {
+ if (item.getName().equals("item")) {
+ String jid = item.getAttribute("jid");
+ String name = item.getAttribute("name");
+ String subscription = item.getAttribute("subscription");
+ Contact contact = account.getRoster().getContact(jid);
+ if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
+ contact.setServerName(name);
+ }
+ if (subscription.equals("remove")) {
+ contact.resetOption(Contact.Options.IN_ROSTER);
+ contact.resetOption(Contact.Options.DIRTY_DELETE);
+ contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
+ } else {
+ contact.setOption(Contact.Options.IN_ROSTER);
+ contact.resetOption(Contact.Options.DIRTY_PUSH);
+ contact.parseSubscriptionFromElement(item);
+ }
+ }
+ }
+ mXmppConnectionService.updateRosterUi();
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.hasChild("query", "jabber:iq:roster")) {
+ String from = packet.getFrom();
+ if ((from == null) || (from.equals(account.getJid()))) {
+ Element query = packet.findChild("query");
+ this.rosterItems(account, query);
+ }
+ } else if (packet
+ .hasChild("open", "http://jabber.org/protocol/ibb")
+ || packet
+ .hasChild("data", "http://jabber.org/protocol/ibb")) {
+ mXmppConnectionService.getJingleConnectionManager().deliverIbbPacket(account, packet);
+ } else if (packet.hasChild("query",
+ "http://jabber.org/protocol/disco#info")) {
+ IqPacket iqResponse = packet
+ .generateRespone(IqPacket.TYPE_RESULT);
+ Element query = iqResponse.addChild("query",
+ "http://jabber.org/protocol/disco#info");
+ query.addChild("feature").setAttribute("var",
+ "urn:xmpp:jingle:1");
+ query.addChild("feature").setAttribute("var",
+ "urn:xmpp:jingle:apps:file-transfer:3");
+ query.addChild("feature").setAttribute("var",
+ "urn:xmpp:jingle:transports:s5b:1");
+ query.addChild("feature").setAttribute("var",
+ "urn:xmpp:jingle:transports:ibb:1");
+ if (mXmppConnectionService.confirmMessages()) {
+ query.addChild("feature").setAttribute("var",
+ "urn:xmpp:receipts");
+ }
+ account.getXmppConnection().sendIqPacket(iqResponse, null);
+ } else {
+ if ((packet.getType() == IqPacket.TYPE_GET)
+ || (packet.getType() == IqPacket.TYPE_SET)) {
+ IqPacket response = packet
+ .generateRespone(IqPacket.TYPE_ERROR);
+ Element error = response.addChild("error");
+ error.setAttribute("type", "cancel");
+ error.addChild("feature-not-implemented",
+ "urn:ietf:params:xml:ns:xmpp-stanzas");
+ account.getXmppConnection().sendIqPacket(response, null);
+ }
+ }
+ }
+
+}
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index 598cf830..60d8fc6b 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -1,5 +1,6 @@
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.entities.Account;
@@ -8,25 +9,29 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
-public class MessageParser extends AbstractParser {
+public class MessageParser extends AbstractParser implements
+ OnMessagePacketReceived {
+
+ private long lastCarbonMessageReceived = -XmppConnectionService.CARBON_GRACE_PERIOD;
public MessageParser(XmppConnectionService service) {
super(service);
}
- public Message parseChat(MessagePacket packet, Account account) {
+ private Message parseChat(MessagePacket packet, Account account) {
String[] fromParts = packet.getFrom().split("/");
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, fromParts[0], false);
conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
- updateLastseen(packet, account,true);
+ updateLastseen(packet, account, true);
String pgpBody = getPgpBody(packet);
Message finishedMessage;
if (pgpBody != null) {
- finishedMessage = new Message(conversation, packet.getFrom(), pgpBody,
- Message.ENCRYPTION_PGP, Message.STATUS_RECIEVED);
+ finishedMessage = new Message(conversation, packet.getFrom(),
+ pgpBody, Message.ENCRYPTION_PGP, Message.STATUS_RECIEVED);
} else {
finishedMessage = new Message(conversation, packet.getFrom(),
packet.getBody(), Message.ENCRYPTION_NONE,
@@ -36,13 +41,13 @@ public class MessageParser extends AbstractParser {
return finishedMessage;
}
- public Message parseOtrChat(MessagePacket packet, Account account) {
+ private Message parseOtrChat(MessagePacket packet, Account account) {
boolean properlyAddressed = (packet.getTo().split("/").length == 2)
|| (account.countPresences() == 1);
String[] fromParts = packet.getFrom().split("/");
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, fromParts[0], false);
- updateLastseen(packet, account,true);
+ updateLastseen(packet, account, true);
String body = packet.getBody();
if (!conversation.hasValidOtrSession()) {
if (properlyAddressed) {
@@ -84,37 +89,42 @@ public class MessageParser extends AbstractParser {
conversation.setSymmetricKey(CryptoHelper.hexToBytes(key));
return null;
}
- conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
- Message finishedMessage = new Message(conversation, packet.getFrom(), body,
- Message.ENCRYPTION_OTR, Message.STATUS_RECIEVED);
+ conversation
+ .setLatestMarkableMessageId(getMarkableMessageId(packet));
+ Message finishedMessage = new Message(conversation,
+ packet.getFrom(), body, Message.ENCRYPTION_OTR,
+ Message.STATUS_RECIEVED);
finishedMessage.setTime(getTimestamp(packet));
return finishedMessage;
} catch (Exception e) {
String receivedId = packet.getId();
- if (receivedId!=null) {
- mXmppConnectionService.replyWithNotAcceptable(account,packet);
+ if (receivedId != null) {
+ mXmppConnectionService.replyWithNotAcceptable(account, packet);
}
conversation.endOtrIfNeeded();
return null;
}
}
- public Message parseGroupchat(MessagePacket packet, Account account) {
+ private Message parseGroupchat(MessagePacket packet, Account account) {
int status;
String[] fromParts = packet.getFrom().split("/");
+ if (mXmppConnectionService.find(account.pendingConferenceLeaves,account,fromParts[0]) != null) {
+ return null;
+ }
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, fromParts[0], true);
if (packet.hasChild("subject")) {
conversation.getMucOptions().setSubject(
packet.findChild("subject").getContent());
- mXmppConnectionService.updateUi(conversation, false);
+ mXmppConnectionService.updateConversationUi();
return null;
}
if ((fromParts.length == 1)) {
return null;
}
String counterPart = fromParts[1];
- if (counterPart.equals(conversation.getMucOptions().getNick())) {
+ if (counterPart.equals(conversation.getMucOptions().getActualNick())) {
if (mXmppConnectionService.markMessage(conversation,
packet.getId(), Message.STATUS_SEND)) {
return null;
@@ -128,17 +138,17 @@ public class MessageParser extends AbstractParser {
conversation.setLatestMarkableMessageId(getMarkableMessageId(packet));
Message finishedMessage;
if (pgpBody == null) {
- finishedMessage = new Message(conversation, counterPart, packet.getBody(),
- Message.ENCRYPTION_NONE, status);
+ finishedMessage = new Message(conversation, counterPart,
+ packet.getBody(), Message.ENCRYPTION_NONE, status);
} else {
- finishedMessage= new Message(conversation, counterPart, pgpBody,
+ finishedMessage = new Message(conversation, counterPart, pgpBody,
Message.ENCRYPTION_PGP, status);
}
finishedMessage.setTime(getTimestamp(packet));
return finishedMessage;
}
- public Message parseCarbonMessage(MessagePacket packet, Account account) {
+ private Message parseCarbonMessage(MessagePacket packet, Account account) {
int status;
String fullJid;
Element forwarded;
@@ -155,14 +165,21 @@ public class MessageParser extends AbstractParser {
return null;
}
Element message = forwarded.findChild("message");
- if ((message == null) || (!message.hasChild("body")))
- return null; // either malformed or boring
+ if ((message == null) || (!message.hasChild("body"))) {
+ if (status == Message.STATUS_RECIEVED) {
+ parseNormal(message, account);
+ }
+ return null;
+ }
if (status == Message.STATUS_RECIEVED) {
fullJid = message.getAttribute("from");
- updateLastseen(message, account,true);
+ updateLastseen(message, account, true);
} else {
fullJid = message.getAttribute("to");
}
+ if (fullJid==null) {
+ return null;
+ }
String[] parts = fullJid.split("/");
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, parts[0], false);
@@ -170,38 +187,49 @@ public class MessageParser extends AbstractParser {
String pgpBody = getPgpBody(message);
Message finishedMessage;
if (pgpBody != null) {
- finishedMessage = new Message(conversation, fullJid, pgpBody,Message.ENCRYPTION_PGP, status);
+ finishedMessage = new Message(conversation, fullJid, pgpBody,
+ Message.ENCRYPTION_PGP, status);
} else {
String body = message.findChild("body").getContent();
- finishedMessage= new Message(conversation, fullJid, body,Message.ENCRYPTION_NONE, status);
+ finishedMessage = new Message(conversation, fullJid, body,
+ Message.ENCRYPTION_NONE, status);
}
finishedMessage.setTime(getTimestamp(message));
return finishedMessage;
}
- public void parseError(MessagePacket packet, Account account) {
+ private void parseError(MessagePacket packet, Account account) {
String[] fromParts = packet.getFrom().split("/");
mXmppConnectionService.markMessage(account, fromParts[0],
packet.getId(), Message.STATUS_SEND_FAILED);
}
-
- public void parseNormal(MessagePacket packet, Account account) {
- if (packet.hasChild("displayed","urn:xmpp:chat-markers:0")) {
- String id = packet.findChild("displayed","urn:xmpp:chat-markers:0").getAttribute("id");
- String[] fromParts = packet.getFrom().split("/");
- updateLastseen(packet, account,true);
- mXmppConnectionService.markMessage(account,fromParts[0], id, Message.STATUS_SEND_DISPLAYED);
- } else if (packet.hasChild("received","urn:xmpp:chat-markers:0")) {
- String id = packet.findChild("received","urn:xmpp:chat-markers:0").getAttribute("id");
- String[] fromParts = packet.getFrom().split("/");
- updateLastseen(packet, account,false);
- mXmppConnectionService.markMessage(account,fromParts[0], id, Message.STATUS_SEND_RECEIVED);
+
+ private void parseNormal(Element packet, Account account) {
+ if (packet.hasChild("displayed", "urn:xmpp:chat-markers:0")) {
+ String id = packet
+ .findChild("displayed", "urn:xmpp:chat-markers:0")
+ .getAttribute("id");
+ String[] fromParts = packet.getAttribute("from").split("/");
+ updateLastseen(packet, account, true);
+ mXmppConnectionService.markMessage(account, fromParts[0], id,
+ Message.STATUS_SEND_DISPLAYED);
+ } else if (packet.hasChild("received", "urn:xmpp:chat-markers:0")) {
+ String id = packet.findChild("received", "urn:xmpp:chat-markers:0")
+ .getAttribute("id");
+ String[] fromParts = packet.getAttribute("from").split("/");
+ updateLastseen(packet, account, false);
+ mXmppConnectionService.markMessage(account, fromParts[0], id,
+ Message.STATUS_SEND_RECEIVED);
} else if (packet.hasChild("x")) {
Element x = packet.findChild("x");
if (x.hasChild("invite")) {
- Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, packet.getFrom(),
- true);
- mXmppConnectionService.updateUi(conversation, false);
+ Conversation conversation = mXmppConnectionService
+ .findOrCreateConversation(account,
+ packet.getAttribute("from"), true);
+ if (!conversation.getMucOptions().online()) {
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
}
}
@@ -215,7 +243,7 @@ public class MessageParser extends AbstractParser {
return child.getContent();
}
}
-
+
private String getMarkableMessageId(Element message) {
if (message.hasChild("markable", "urn:xmpp:chat-markers:0")) {
return message.getAttribute("id");
@@ -224,5 +252,83 @@ public class MessageParser extends AbstractParser {
}
}
-
+ @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) > XmppConnectionService.CARBON_GRACE_PERIOD;
+ }
+
+ if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
+ if ((packet.getBody() != null)
+ && (packet.getBody().startsWith("?OTR"))) {
+ message = this.parseOtrChat(packet, account);
+ if (message != null) {
+ message.markUnread();
+ }
+ } else if (packet.hasChild("body")) {
+ message = this.parseChat(packet, account);
+ message.markUnread();
+ } else if (packet.hasChild("received") || (packet.hasChild("sent"))) {
+ message = this.parseCarbonMessage(packet, account);
+ if (message != null) {
+ if (message.getStatus() == Message.STATUS_SEND) {
+ lastCarbonMessageReceived = SystemClock
+ .elapsedRealtime();
+ notify = false;
+ message.getConversation().markRead();
+ } else {
+ message.markUnread();
+ }
+ }
+ }
+
+ } else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
+ message = this.parseGroupchat(packet, account);
+ if (message != null) {
+ if (message.getStatus() == Message.STATUS_RECIEVED) {
+ message.markUnread();
+ } else {
+ message.getConversation().markRead();
+ lastCarbonMessageReceived = SystemClock
+ .elapsedRealtime();
+ notify = false;
+ }
+ }
+ } else if (packet.getType() == MessagePacket.TYPE_ERROR) {
+ this.parseError(packet, account);
+ return;
+ } else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
+ this.parseNormal(packet, account);
+ }
+ if ((message == null) || (message.getBody() == null)) {
+ return;
+ }
+ if ((mXmppConnectionService.confirmMessages())
+ && ((packet.getId() != null))) {
+ MessagePacket receivedPacket = new MessagePacket();
+ receivedPacket.setType(MessagePacket.TYPE_NORMAL);
+ receivedPacket.setTo(message.getCounterpart());
+ receivedPacket.setFrom(account.getFullJid());
+ if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
+ Element received = receivedPacket.addChild("received",
+ "urn:xmpp:chat-markers:0");
+ received.setAttribute("id", packet.getId());
+ account.getXmppConnection().sendMessagePacket(receivedPacket);
+ } else if (packet.hasChild("request", "urn:xmpp:receipts")) {
+ Element received = receivedPacket.addChild("received",
+ "urn:xmpp:receipts");
+ received.setAttribute("id", packet.getId());
+ account.getXmppConnection().sendMessagePacket(receivedPacket);
+ }
+ }
+ Conversation conversation = message.getConversation();
+ conversation.getMessages().add(message);
+ if (packet.getType() != MessagePacket.TYPE_ERROR) {
+ mXmppConnectionService.databaseBackend.createMessage(message);
+ }
+ mXmppConnectionService.notifyUi(conversation, notify);
+ }
}
diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java
index 8cc57bad..33f4185f 100644
--- a/src/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/eu/siacs/conversations/parser/PresenceParser.java
@@ -5,12 +5,15 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.generator.PresenceGenerator;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
-public class PresenceParser extends AbstractParser {
-
+public class PresenceParser extends AbstractParser implements
+ OnPresencePacketReceived {
+
public PresenceParser(XmppConnectionService service) {
super(service);
}
@@ -18,26 +21,24 @@ public class PresenceParser extends AbstractParser {
public void parseConferencePresence(PresencePacket packet, Account account) {
PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine();
if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
- Conversation muc = mXmppConnectionService.findMuc(packet
- .getAttribute("from").split("/")[0], account);
+ Conversation muc = mXmppConnectionService.find(account,packet
+ .getAttribute("from").split("/")[0]);
if (muc != null) {
muc.getMucOptions().processPacket(packet, mPgpEngine);
}
} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
- Conversation muc = mXmppConnectionService.findMuc(packet
- .getAttribute("from").split("/")[0], account);
+ Conversation muc = mXmppConnectionService.find(account,packet
+ .getAttribute("from").split("/")[0]);
if (muc != null) {
- int error = muc.getMucOptions().getError();
muc.getMucOptions().processPacket(packet, mPgpEngine);
- if (muc.getMucOptions().getError() != error) {
- mXmppConnectionService.updateUi(muc, false);
- }
}
}
+ mXmppConnectionService.updateConversationUi();
}
public void parseContactPresence(PresencePacket packet, Account account) {
- if (packet.getFrom()==null) {
+ PresenceGenerator mPresenceGenerator = mXmppConnectionService.getPresenceGenerator();
+ if (packet.getFrom() == null) {
return;
}
String[] fromParts = packet.getFrom().split("/");
@@ -75,9 +76,9 @@ public class PresenceParser extends AbstractParser {
}
}
boolean online = sizeBefore < contact.getPresences().size();
- updateLastseen(packet, account,true);
+ updateLastseen(packet, account, true);
mXmppConnectionService.onContactStatusChanged
- .onContactStatusChanged(contact,online);
+ .onContactStatusChanged(contact, online);
}
} else if (type.equals("unavailable")) {
if (fromParts.length != 2) {
@@ -86,22 +87,27 @@ public class PresenceParser extends AbstractParser {
contact.removePresence(fromParts[1]);
}
mXmppConnectionService.onContactStatusChanged
- .onContactStatusChanged(contact,false);
+ .onContactStatusChanged(contact, false);
} else if (type.equals("subscribe")) {
if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
- mXmppConnectionService.sendPresenceUpdatesTo(contact);
- contact.setOption(Contact.Options.FROM);
- contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
- if ((contact.getOption(Contact.Options.ASKING))
- && (!contact.getOption(Contact.Options.TO))) {
- mXmppConnectionService
- .requestPresenceUpdatesFrom(contact);
- }
+ mXmppConnectionService.sendPresencePacket(account, mPresenceGenerator.sendPresenceUpdatesTo(contact));
} else {
contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST);
}
}
}
+ mXmppConnectionService.updateRosterUi();
+ }
+
+ @Override
+ public void onPresencePacketReceived(Account account, PresencePacket packet) {
+ if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
+ this.parseConferencePresence(packet, account);
+ } else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
+ this.parseConferencePresence(packet, account);
+ } else {
+ this.parseContactPresence(packet, account);
+ }
}
}
diff --git a/src/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
index fbf45d25..7643076a 100644
--- a/src/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -116,8 +116,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return cursor.getInt(0);
}
- public List<Conversation> getConversations(int status) {
- List<Conversation> list = new ArrayList<Conversation>();
+ public CopyOnWriteArrayList<Conversation> getConversations(int status) {
+ CopyOnWriteArrayList<Conversation> list = new CopyOnWriteArrayList<Conversation>();
SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = { "" + status };
Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index 3db52753..0ac1adf7 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.services;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
@@ -9,6 +10,7 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
@@ -18,6 +20,7 @@ import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -25,12 +28,12 @@ import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.generator.MessageGenerator;
+import eu.siacs.conversations.generator.PresenceGenerator;
+import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.parser.MessageParser;
import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
-import eu.siacs.conversations.ui.OnAccountListChangedListener;
-import eu.siacs.conversations.ui.OnConversationListChangedListener;
import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
@@ -42,8 +45,6 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
-import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
-import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
@@ -86,28 +87,31 @@ public class XmppConnectionService extends Service {
private static final int PING_MIN_INTERVAL = 30;
private static final int PING_TIMEOUT = 10;
private static final int CONNECT_TIMEOUT = 90;
- private static final long CARBON_GRACE_PERIOD = 60000L;
+ public static final long CARBON_GRACE_PERIOD = 60000L;
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
private MessageParser mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this);
+ private IqParser mIqParser = new IqParser(this);
private MessageGenerator mMessageGenerator = new MessageGenerator();
-
+ private PresenceGenerator mPresenceGenerator = new PresenceGenerator();
+
private List<Account> accounts;
- private List<Conversation> conversations = null;
+ private CopyOnWriteArrayList<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this);
- private OnConversationListChangedListener convChangedListener = null;
+ private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
- private OnAccountListChangedListener accountChangedListener = null;
+ private OnAccountUpdate mOnAccountUpdate = null;
+ private OnRosterUpdate mOnRosterUpdate = null;
private OnTLSExceptionReceived tlsException = null;
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
@Override
public void onContactStatusChanged(Contact contact, boolean online) {
- Conversation conversation = findActiveConversation(contact);
+ Conversation conversation = find(getConversations(),contact);
if (conversation != null) {
conversation.endOtrIfNeeded();
if (online && (contact.getPresences().size() == 1)) {
@@ -124,8 +128,6 @@ public class XmppConnectionService extends Service {
private SecureRandom mRandom;
- private long lastCarbonMessageReceived = -CARBON_GRACE_PERIOD;
-
private ContentObserver contactObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
@@ -138,103 +140,20 @@ public class XmppConnectionService extends Service {
};
private final IBinder mBinder = new XmppConnectionBinder();
- private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
-
- @Override
- public void onMessagePacketReceived(Account account,
- MessagePacket packet) {
- Message message = null;
- boolean notify = true;
- if (getPreferences().getBoolean(
- "notification_grace_period_after_carbon_received", true)) {
- notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD;
- }
-
- if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
- if ((packet.getBody() != null)
- && (packet.getBody().startsWith("?OTR"))) {
- message = mMessageParser.parseOtrChat(packet, account);
- if (message != null) {
- message.markUnread();
- }
- } else if (packet.hasChild("body")) {
- message = mMessageParser.parseChat(packet, account);
- message.markUnread();
- } else if (packet.hasChild("received")
- || (packet.hasChild("sent"))) {
- message = mMessageParser
- .parseCarbonMessage(packet, account);
- if (message != null) {
- if (message.getStatus() == Message.STATUS_SEND) {
- lastCarbonMessageReceived = SystemClock
- .elapsedRealtime();
- notify = false;
- message.getConversation().markRead();
- } else {
- message.markUnread();
- }
- }
- }
-
- } else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
- message = mMessageParser.parseGroupchat(packet, account);
- if (message != null) {
- if (message.getStatus() == Message.STATUS_RECIEVED) {
- message.markUnread();
- } else {
- message.getConversation().markRead();
- notify = false;
- }
- }
- } else if (packet.getType() == MessagePacket.TYPE_ERROR) {
- mMessageParser.parseError(packet, account);
- return;
- } else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
- mMessageParser.parseNormal(packet, account);
- }
- if ((message == null) || (message.getBody() == null)) {
- return;
- }
- if ((confirmMessages()) && ((packet.getId() != null))) {
- MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
- receivedPacket.setTo(message.getCounterpart());
- receivedPacket.setFrom(account.getFullJid());
- if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:chat-markers:0");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(
- receivedPacket);
- } else if (packet.hasChild("request", "urn:xmpp:receipts")) {
- Element received = receivedPacket.addChild("received",
- "urn:xmpp:receipts");
- received.setAttribute("id", packet.getId());
- account.getXmppConnection().sendMessagePacket(
- receivedPacket);
- }
- }
- Conversation conversation = message.getConversation();
- conversation.getMessages().add(message);
- if (packet.getType() != MessagePacket.TYPE_ERROR) {
- databaseBackend.createMessage(message);
- }
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- } else {
- UIHelper.updateNotification(getApplicationContext(),
- getConversations(), message.getConversation(), notify);
- }
- }
- };
private OnStatusChanged statusListener = new OnStatusChanged() {
@Override
public void onStatusChanged(Account account) {
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();;
}
if (account.getStatus() == Account.STATUS_ONLINE) {
+ for(Conversation conversation : account.pendingConferenceLeaves) {
+ leaveMuc(conversation);
+ }
+ for(Conversation conversation : account.pendingConferenceJoins) {
+ joinMuc(conversation);
+ }
mJingleConnectionManager.cancelInTransmission();
List<Conversation> conversations = getConversations();
for (int i = 0; i < conversations.size(); ++i) {
@@ -269,73 +188,6 @@ public class XmppConnectionService extends Service {
}
};
- private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() {
-
- @Override
- public void onPresencePacketReceived(final Account account,
- PresencePacket packet) {
- if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
- mPresenceParser.parseConferencePresence(packet, account);
- } else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) {
- mPresenceParser.parseConferencePresence(packet, account);
- } else {
- mPresenceParser.parseContactPresence(packet, account);
- }
- }
- };
-
- private OnIqPacketReceived unknownIqListener = new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.hasChild("query", "jabber:iq:roster")) {
- String from = packet.getFrom();
- if ((from == null) || (from.equals(account.getJid()))) {
- Element query = packet.findChild("query");
- processRosterItems(account, query);
- } else {
- Log.d(LOGTAG, "unauthorized roster push from: " + from);
- }
- } else if (packet
- .hasChild("open", "http://jabber.org/protocol/ibb")
- || packet
- .hasChild("data", "http://jabber.org/protocol/ibb")) {
- XmppConnectionService.this.mJingleConnectionManager
- .deliverIbbPacket(account, packet);
- } else if (packet.hasChild("query",
- "http://jabber.org/protocol/disco#info")) {
- IqPacket iqResponse = packet
- .generateRespone(IqPacket.TYPE_RESULT);
- Element query = iqResponse.addChild("query",
- "http://jabber.org/protocol/disco#info");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:apps:file-transfer:3");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:s5b:1");
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:jingle:transports:ibb:1");
- if (confirmMessages()) {
- query.addChild("feature").setAttribute("var",
- "urn:xmpp:receipts");
- }
- account.getXmppConnection().sendIqPacket(iqResponse, null);
- } else {
- if ((packet.getType() == IqPacket.TYPE_GET)
- || (packet.getType() == IqPacket.TYPE_SET)) {
- IqPacket response = packet
- .generateRespone(IqPacket.TYPE_ERROR);
- Element error = response.addChild("error");
- error.setAttribute("type", "cancel");
- error.addChild("feature-not-implemented",
- "urn:ietf:params:xml:ns:xmpp-stanzas");
- account.getXmppConnection().sendIqPacket(response, null);
- }
- }
- }
- };
-
private OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@Override
@@ -350,6 +202,21 @@ public class XmppConnectionService extends Service {
private PendingIntent pendingPingIntent = null;
private WakeLock wakeLock;
private PowerManager pm;
+ private OnBindListener mOnBindListener = new OnBindListener() {
+
+ @Override
+ public void onBind(final Account account) {
+ account.getRoster().clearPresences();
+ account.clearPresences(); // self presences
+ account.pendingConferenceJoins.clear();
+ account.pendingConferenceLeaves.clear();
+ fetchRosterFromServer(account);
+ fetchBookmarks(account);
+ sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
+ connectMultiModeConversations(account);
+ updateConversationUi();
+ }
+ };
public PgpEngine getPgpEngine() {
if (pgpServiceConnection.isBound()) {
@@ -401,39 +268,12 @@ public class XmppConnectionService extends Service {
return message;
}
- public Conversation findMuc(String name, Account account) {
- for (Conversation conversation : this.conversations) {
- if (conversation.getContactJid().split("/")[0].equals(name)
- && (conversation.getAccount() == account)) {
- return conversation;
- }
- }
- return null;
+ public Conversation find(Bookmark bookmark) {
+ return find(bookmark.getAccount(),bookmark.getJid());
}
-
- private void processRosterItems(Account account, Element elements) {
- String version = elements.getAttribute("ver");
- if (version != null) {
- account.getRoster().setVersion(version);
- }
- for (Element item : elements.getChildren()) {
- if (item.getName().equals("item")) {
- String jid = item.getAttribute("jid");
- String name = item.getAttribute("name");
- String subscription = item.getAttribute("subscription");
- Contact contact = account.getRoster().getContact(jid);
- if (!contact.getOption(Contact.Options.DIRTY_PUSH)) {
- contact.setServerName(name);
- }
- if (subscription.equals("remove")) {
- contact.resetOption(Contact.Options.IN_ROSTER);
- contact.resetOption(Contact.Options.DIRTY_DELETE);
- } else {
- contact.setOption(Contact.Options.IN_ROSTER);
- contact.parseSubscriptionFromElement(item);
- }
- }
- }
+
+ public Conversation find(Account account, String jid) {
+ return find(getConversations(),account,jid);
}
public class XmppConnectionBinder extends Binder {
@@ -508,13 +348,16 @@ public class XmppConnectionService extends Service {
// in any case. reschedule wakup call
this.scheduleWakeupCall(PING_MAX_INTERVAL, true);
}
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();
}
}
}
if (wakeLock.isHeld()) {
- try { wakeLock.release();} catch (RuntimeException re) {}
+ try {
+ wakeLock.release();
+ } catch (RuntimeException re) {
+ }
}
return START_STICKY;
}
@@ -618,11 +461,11 @@ public class XmppConnectionService extends Service {
account.setResource(sharedPref.getString("resource", "mobile")
.toLowerCase(Locale.getDefault()));
XmppConnection connection = new XmppConnection(account, this);
- connection.setOnMessagePacketReceivedListener(this.messageListener);
+ connection.setOnMessagePacketReceivedListener(this.mMessageParser);
connection.setOnStatusChangedListener(this.statusListener);
- connection.setOnPresencePacketReceivedListener(this.presenceListener);
+ connection.setOnPresencePacketReceivedListener(this.mPresenceParser);
connection
- .setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
+ .setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
connection
.setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
@@ -637,20 +480,7 @@ public class XmppConnectionService extends Service {
}
}
});
- connection.setOnBindListener(new OnBindListener() {
-
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- account.clearPresences(); // self presences
- fetchRosterFromServer(account);
- sendPresence(account);
- connectMultiModeConversations(account);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
- }
- });
+ connection.setOnBindListener(this.mOnBindListener);
return connection;
}
@@ -691,25 +521,24 @@ public class XmppConnectionService extends Service {
message.setStatus(Message.STATUS_WAITING);
} else if (conv.hasValidOtrSession()
&& conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
- message.setPresence(conv.getOtrSession().getSessionID().getUserID());
- try {
- packet = mMessageGenerator.generateOtrChat(message);
- send = true;
- message.setStatus(Message.STATUS_SEND);
- } catch (OtrException e) {
- Log.e(LOGTAG,"error generating otr packet");
- packet = null;
- }
+ message.setPresence(conv.getOtrSession().getSessionID()
+ .getUserID());
+ packet = mMessageGenerator.generateOtrChat(message);
+ send = true;
+ message.setStatus(Message.STATUS_SEND);
+
} else if (message.getPresence() == null) {
message.setStatus(Message.STATUS_WAITING);
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
message.getConversation().endOtrIfNeeded();
+ message.getConversation().failWaitingOtrMessages();
packet = mMessageGenerator.generatePgpChat(message);
message.setStatus(Message.STATUS_SEND);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
+ message.getConversation().failWaitingOtrMessages();
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
}
@@ -744,11 +573,9 @@ public class XmppConnectionService extends Service {
databaseBackend.createMessage(message);
}
conv.getMessages().add(message);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
if ((send) && (packet != null)) {
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account, packet);
}
}
@@ -782,9 +609,11 @@ public class XmppConnectionService extends Service {
}
}
} else {
- if (message.getConversation().getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
+ if (message.getConversation().getOtrSession()
+ .getSessionStatus() == SessionStatus.ENCRYPTED) {
if (message.getType() == Message.TYPE_TEXT) {
- packet = mMessageGenerator.generateOtrChat(message,true);
+ packet = mMessageGenerator.generateOtrChat(message,
+ true);
} else if (message.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(message);
}
@@ -792,9 +621,10 @@ public class XmppConnectionService extends Service {
}
} else if (message.getType() == Message.TYPE_TEXT) {
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
- packet = mMessageGenerator.generateChat(message,true);
- } else if ((message.getEncryption() == Message.ENCRYPTION_DECRYPTED)||(message.getEncryption() == Message.ENCRYPTION_PGP)) {
- packet = mMessageGenerator.generatePgpChat(message,true);
+ packet = mMessageGenerator.generateChat(message, true);
+ } else if ((message.getEncryption() == Message.ENCRYPTION_DECRYPTED)
+ || (message.getEncryption() == Message.ENCRYPTION_PGP)) {
+ packet = mMessageGenerator.generatePgpChat(message, true);
}
} else if (message.getType() == Message.TYPE_IMAGE) {
Presences presences = message.getConversation().getContact()
@@ -813,7 +643,7 @@ public class XmppConnectionService extends Service {
}
}
if (packet != null) {
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account,packet);
markMessage(message, Message.STATUS_SEND);
}
}
@@ -834,14 +664,60 @@ public class XmppConnectionService extends Service {
@Override
public void onIqPacketReceived(final Account account,
IqPacket packet) {
- Element roster = packet.findChild("query");
- if (roster != null) {
+ Element query = packet.findChild("query");
+ if (query != null) {
account.getRoster().markAllAsNotInRoster();
- processRosterItems(account, roster);
+ mIqParser.rosterItems(account, query);
}
}
});
}
+
+ public void fetchBookmarks(Account account) {
+ IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+ Element query = iqPacket.query("jabber:iq:private");
+ query.addChild("storage", "storage:bookmarks");
+ OnIqPacketReceived callback = new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Element query = packet.query();
+ List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ Element storage = query.findChild("storage", "storage:bookmarks");
+ if (storage!=null) {
+ for(Element item : storage.getChildren()) {
+ if (item.getName().equals("conference")) {
+ Bookmark bookmark = Bookmark.parse(item,account);
+ bookmarks.add(bookmark);
+ Conversation conversation = find(bookmark);
+ if (conversation!=null) {
+ conversation.setBookmark(bookmark);
+ } else {
+ if (bookmark.autojoin()) {
+ conversation = findOrCreateConversation(account, bookmark.getJid(), true);
+ conversation.setBookmark(bookmark);
+ joinMuc(conversation);
+ }
+ }
+ }
+ }
+ }
+ account.setBookmarks(bookmarks);
+ }
+ };
+ sendIqPacket(account, iqPacket, callback);
+
+ }
+
+ public void pushBookmarks(Account account) {
+ IqPacket iqPacket = new IqPacket(IqPacket.TYPE_SET);
+ Element query = iqPacket.query("jabber:iq:private");
+ Element storage = query.addChild("storage", "storage:bookmarks");
+ for(Bookmark bookmark : account.getBookmarks()) {
+ storage.addChild(bookmark.toElement());
+ }
+ sendIqPacket(account, iqPacket,null);
+ }
private void mergePhoneContactsWithRoster() {
PhoneHelper.loadPhoneContacts(getApplicationContext(),
@@ -885,7 +761,14 @@ public class XmppConnectionService extends Service {
conv.setMessages(databaseBackend.getMessages(conv, 50));
}
}
- Collections.sort(this.conversations, new Comparator<Conversation>() {
+
+ return this.conversations;
+ }
+
+ public void populateWithOrderedConversations(List<Conversation> list) {
+ list.clear();
+ list.addAll(getConversations());
+ Collections.sort(list, new Comparator<Conversation>() {
@Override
public int compare(Conversation lhs, Conversation rhs) {
Message left = lhs.getLatestMessage();
@@ -899,7 +782,6 @@ public class XmppConnectionService extends Service {
}
}
});
- return this.conversations;
}
public List<Message> getMoreMessages(Conversation conversation,
@@ -916,8 +798,8 @@ public class XmppConnectionService extends Service {
return this.accounts;
}
- public Conversation findActiveConversation(Contact contact) {
- for (Conversation conversation : this.getConversations()) {
+ public Conversation find(List<Conversation> haystack, Contact contact) {
+ for (Conversation conversation : haystack) {
if (conversation.getContact() == contact) {
return conversation;
}
@@ -925,16 +807,24 @@ public class XmppConnectionService extends Service {
return null;
}
+ public Conversation find(List<Conversation> haystack, Account account, String jid) {
+ for (Conversation conversation : haystack) {
+ if ((conversation.getAccount().equals(account))
+ && (conversation.getContactJid().split("/")[0].equals(jid))) {
+ return conversation;
+ }
+ }
+ return null;
+ }
+
+
public Conversation findOrCreateConversation(Account account, String jid,
boolean muc) {
- for (Conversation conv : this.getConversations()) {
- if ((conv.getAccount().equals(account))
- && (conv.getContactJid().split("/")[0].equals(jid))) {
- return conv;
- }
+ Conversation conversation = find(account, jid);
+ if (conversation != null) {
+ return conversation;
}
- Conversation conversation = databaseBackend.findConversation(account,
- jid);
+ conversation = databaseBackend.findConversation(account,jid);
if (conversation != null) {
conversation.setStatus(Conversation.STATUS_AVAILABLE);
conversation.setAccount(account);
@@ -964,36 +854,31 @@ public class XmppConnectionService extends Service {
this.databaseBackend.createConversation(conversation);
}
this.conversations.add(conversation);
- if ((account.getStatus() == Account.STATUS_ONLINE)
- && (conversation.getMode() == Conversation.MODE_MULTI)) {
- joinMuc(conversation);
- }
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
return conversation;
}
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());
+ }
leaveMuc(conversation);
} else {
conversation.endOtrIfNeeded();
}
this.databaseBackend.updateConversation(conversation);
this.conversations.remove(conversation);
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public void clearConversationHistory(Conversation conversation) {
this.databaseBackend.deleteMessagesInConversation(conversation);
this.fileBackend.removeFiles(conversation);
conversation.getMessages().clear();
- if (this.convChangedListener != null) {
- this.convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public int getConversationCount() {
@@ -1004,17 +889,14 @@ public class XmppConnectionService extends Service {
databaseBackend.createAccount(account);
this.accounts.add(account);
this.reconnectAccount(account, false);
- if (accountChangedListener != null)
- accountChangedListener.onAccountListChangedListener();
+ updateAccountUi();
}
public void updateAccount(Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
reconnectAccount(account, false);
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
- }
+ updateAccountUi();
UIHelper.showErrorNotification(getApplicationContext(), getAccounts());
}
@@ -1024,32 +906,37 @@ public class XmppConnectionService extends Service {
}
databaseBackend.deleteAccount(account);
this.accounts.remove(account);
- if (accountChangedListener != null) {
- accountChangedListener.onAccountListChangedListener();
- }
+ updateAccountUi();
UIHelper.showErrorNotification(getApplicationContext(), getAccounts());
}
public void setOnConversationListChangedListener(
- OnConversationListChangedListener listener) {
- this.convChangedListener = listener;
+ OnConversationUpdate listener) {
+ this.mOnConversationUpdate = listener;
this.convChangedListenerCount++;
}
public void removeOnConversationListChangedListener() {
this.convChangedListenerCount--;
if (this.convChangedListenerCount == 0) {
- this.convChangedListener = null;
+ this.mOnConversationUpdate = null;
}
}
- public void setOnAccountListChangedListener(
- OnAccountListChangedListener listener) {
- this.accountChangedListener = listener;
+ public void setOnAccountListChangedListener(OnAccountUpdate listener) {
+ this.mOnAccountUpdate = listener;
}
public void removeOnAccountListChangedListener() {
- this.accountChangedListener = null;
+ this.mOnAccountUpdate = null;
+ }
+
+ public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ this.mOnRosterUpdate = listener;
+ }
+
+ public void removeOnRosterUpdateListener() {
+ this.mOnRosterUpdate = null;
}
public void connectMultiModeConversations(Account account) {
@@ -1065,33 +952,35 @@ public class XmppConnectionService extends Service {
public void joinMuc(Conversation conversation) {
Account account = conversation.getAccount();
- String[] mucParts = conversation.getContactJid().split("/");
- String muc;
- String nick;
- if (mucParts.length == 2) {
- muc = mucParts[0];
- nick = mucParts[1];
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ Log.d(LOGTAG,"joining conversation "+conversation.getContactJid());
+ String nick = conversation.getMucOptions().getProposedNick();
+ conversation.getMucOptions().setJoinNick(nick);
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("to",conversation.getMucOptions().getJoinJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
+ String sig = account.getPgpSignature();
+ if (sig != null) {
+ packet.addChild("status").setContent("online");
+ packet.addChild("x", "jabber:x:signed").setContent(sig);
+ }
+ if (conversation.getMessages().size() != 0) {
+ final SimpleDateFormat mDateFormat = new SimpleDateFormat(
+ "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
+ mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Date date = new Date(
+ conversation.getLatestMessage().getTimeSent() + 1000);
+ x.addChild("history").setAttribute("since",
+ mDateFormat.format(date));
+ }
+ packet.addChild(x);
+ sendPresencePacket(account, packet);
} else {
- muc = mucParts[0];
- nick = account.getUsername();
- }
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", muc + "/" + nick);
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
- String sig = account.getPgpSignature();
- if (sig != null) {
- packet.addChild("status").setContent("online");
- packet.addChild("x", "jabber:x:signed").setContent(sig);
- }
- if (conversation.getMessages().size() != 0) {
- final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",Locale.US);
- mDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- Date date = new Date(conversation.getLatestMessage().getTimeSent() + 1000);
- x.addChild("history").setAttribute("since",mDateFormat.format(date));
+ account.pendingConferenceJoins.add(conversation);
}
- packet.addChild(x);
- account.getXmppConnection().sendPresencePacket(packet);
}
private OnRenameListener renameListener = null;
@@ -1102,6 +991,7 @@ public class XmppConnectionService extends Service {
public void renameInMuc(final Conversation conversation, final String nick) {
final MucOptions options = conversation.getMucOptions();
+ options.setJoinNick(nick);
if (options.online()) {
Account account = conversation.getAccount();
options.setOnRenameListener(new OnRenameListener() {
@@ -1112,17 +1002,19 @@ public class XmppConnectionService extends Service {
renameListener.onRename(success);
}
if (success) {
- String jid = conversation.getContactJid().split("/")[0]
- + "/" + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(conversation.getMucOptions().getJoinJid());
databaseBackend.updateConversation(conversation);
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
}
}
});
options.flagAboutToRename();
PresencePacket packet = new PresencePacket();
- packet.setAttribute("to",
- conversation.getContactJid().split("/")[0] + "/" + nick);
+ packet.setAttribute("to",options.getJoinJid());
packet.setAttribute("from", conversation.getAccount().getFullJid());
String sig = account.getPgpSignature();
@@ -1130,29 +1022,37 @@ public class XmppConnectionService extends Service {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
-
- account.getXmppConnection().sendPresencePacket(packet, null);
+ sendPresencePacket(account,packet);
} else {
- String jid = conversation.getContactJid().split("/")[0] + "/"
- + nick;
- conversation.setContactJid(jid);
+ conversation.setContactJid(options.getJoinJid());
databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ Bookmark bookmark = conversation.getBookmark();
+ if (bookmark!=null) {
+ bookmark.setNick(nick);
+ pushBookmarks(bookmark.getAccount());
+ }
joinMuc(conversation);
}
}
}
public void leaveMuc(Conversation conversation) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("to", conversation.getContactJid().split("/")[0]
- + "/" + conversation.getMucOptions().getNick());
- packet.setAttribute("from", conversation.getAccount().getFullJid());
- packet.setAttribute("type", "unavailable");
- Log.d(LOGTAG, "send leaving muc " + packet);
- conversation.getAccount().getXmppConnection()
- .sendPresencePacket(packet);
- conversation.getMucOptions().setOffline();
+ Account account = conversation.getAccount();
+ account.pendingConferenceJoins.remove(conversation);
+ account.pendingConferenceLeaves.remove(conversation);
+ if (account.getStatus() == Account.STATUS_ONLINE) {
+ PresencePacket packet = new PresencePacket();
+ packet.setAttribute("to", conversation.getMucOptions().getJoinJid());
+ packet.setAttribute("from", conversation.getAccount().getFullJid());
+ packet.setAttribute("type", "unavailable");
+ sendPresencePacket(conversation.getAccount(),packet);
+ conversation.getMucOptions().setOffline();
+ conversation.deregisterWithBookmark();
+ Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ } else {
+ account.pendingConferenceLeaves.add(conversation);
+ }
}
public void disconnect(Account account, boolean force) {
@@ -1219,18 +1119,19 @@ public class XmppConnectionService extends Service {
&& (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
msg.setPresence(otrSession.getSessionID().getUserID());
if (msg.getType() == Message.TYPE_TEXT) {
- MessagePacket outPacket = mMessageGenerator.generateOtrChat(msg,true);
- if (outPacket!=null) {
+ MessagePacket outPacket = mMessageGenerator
+ .generateOtrChat(msg, true);
+ if (outPacket != null) {
msg.setStatus(Message.STATUS_SEND);
databaseBackend.updateMessage(msg);
- account.getXmppConnection().sendMessagePacket(outPacket);
+ sendMessagePacket(account,outPacket);
}
} else if (msg.getType() == Message.TYPE_IMAGE) {
mJingleConnectionManager.createNewConnection(msg);
}
}
}
- updateUi(conversation, false);
+ notifyUi(conversation, false);
}
public boolean renewSymmetricKey(Conversation conversation) {
@@ -1250,7 +1151,7 @@ public class XmppConnectionService extends Service {
packet.setBody(otrSession
.transformSending(CryptoHelper.FILETRANSFER
+ CryptoHelper.bytesToHex(symmetricKey)));
- account.getXmppConnection().sendMessagePacket(packet);
+ sendMessagePacket(account,packet);
conversation.setSymmetricKey(symmetricKey);
return true;
} catch (OtrException e) {
@@ -1262,26 +1163,28 @@ public class XmppConnectionService extends Service {
public void pushContactToServer(Contact contact) {
contact.resetOption(Contact.Options.DIRTY_DELETE);
+ contact.setOption(Contact.Options.DIRTY_PUSH);
Account account = contact.getAccount();
if (account.getStatus() == Account.STATUS_ONLINE) {
+ boolean ask = contact.getOption(Contact.Options.ASKING);
+ boolean sendUpdates = contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)
+ && contact.getOption(Contact.Options.PREEMPTIVE_GRANT);
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
iq.query("jabber:iq:roster").addChild(contact.asElement());
account.getXmppConnection().sendIqPacket(iq, null);
- if (contact.getOption(Contact.Options.ASKING)) {
- requestPresenceUpdatesFrom(contact);
+ if (sendUpdates) {
+ sendPresencePacket(account, mPresenceGenerator.sendPresenceUpdatesTo(contact));
}
- if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
- Log.d("xmppService", "contact had pending subscription");
- sendPresenceUpdatesTo(contact);
+ if (ask) {
+ sendPresencePacket(account, mPresenceGenerator.requestPresenceUpdatesFrom(contact));
}
- contact.resetOption(Contact.Options.DIRTY_PUSH);
- } else {
- contact.setOption(Contact.Options.DIRTY_PUSH);
}
}
public void deleteContactOnServer(Contact contact) {
+ contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
contact.resetOption(Contact.Options.DIRTY_PUSH);
+ contact.setOption(Contact.Options.DIRTY_DELETE);
Account account = contact.getAccount();
if (account.getStatus() == Account.STATUS_ONLINE) {
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
@@ -1289,55 +1192,9 @@ public class XmppConnectionService extends Service {
item.setAttribute("jid", contact.getJid());
item.setAttribute("subscription", "remove");
account.getXmppConnection().sendIqPacket(iq, null);
- contact.resetOption(Contact.Options.DIRTY_DELETE);
- } else {
- contact.setOption(Contact.Options.DIRTY_DELETE);
}
}
- public void requestPresenceUpdatesFrom(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "subscribe");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void stopPresenceUpdatesFrom(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "unsubscribe");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void stopPresenceUpdatesTo(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "unsubscribed");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void sendPresenceUpdatesTo(Contact contact) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("type", "subscribed");
- packet.setAttribute("to", contact.getJid());
- packet.setAttribute("from", contact.getAccount().getJid());
- contact.getAccount().getXmppConnection().sendPresencePacket(packet);
- }
-
- public void sendPresence(Account account) {
- PresencePacket packet = new PresencePacket();
- packet.setAttribute("from", account.getFullJid());
- String sig = account.getPgpSignature();
- if (sig != null) {
- packet.addChild("status").setContent("online");
- packet.addChild("x", "jabber:x:signed").setContent(sig);
- }
- account.getXmppConnection().sendPresencePacket(packet);
- }
-
public void updateConversation(Conversation conversation) {
this.databaseBackend.updateConversation(conversation);
}
@@ -1366,38 +1223,19 @@ public class XmppConnectionService extends Service {
}).start();
}
- public void sendConversationSubject(Conversation conversation,
- String subject) {
+ public void inviteToConference(Conversation conversation, String contactJid) {
+ Account account = conversation.getAccount();
MessagePacket packet = new MessagePacket();
- packet.setType(MessagePacket.TYPE_GROUPCHAT);
packet.setTo(conversation.getContactJid().split("/")[0]);
- Element subjectChild = new Element("subject");
- subjectChild.setContent(subject);
- packet.addChild(subjectChild);
- packet.setFrom(conversation.getAccount().getJid());
- Account account = conversation.getAccount();
- if (account.getStatus() == Account.STATUS_ONLINE) {
- account.getXmppConnection().sendMessagePacket(packet);
- }
- }
-
- public void inviteToConference(Conversation conversation,
- List<Contact> contacts) {
- for (Contact contact : contacts) {
- MessagePacket packet = new MessagePacket();
- packet.setTo(conversation.getContactJid().split("/")[0]);
- packet.setFrom(conversation.getAccount().getFullJid());
- Element x = new Element("x");
- x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
- Element invite = new Element("invite");
- invite.setAttribute("to", contact.getJid());
- x.addChild(invite);
- packet.addChild(x);
- Log.d(LOGTAG, packet.toString());
- conversation.getAccount().getXmppConnection()
- .sendMessagePacket(packet);
- }
-
+ packet.setFrom(account.getFullJid());
+ Element x = new Element("x");
+ x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
+ Element invite = new Element("invite");
+ invite.setAttribute("to", contactJid);
+ x.addChild(invite);
+ packet.addChild(x);
+ sendMessagePacket(account,packet);
+ Log.d(LOGTAG,packet.toString());
}
public boolean markMessage(Account account, String recipient, String uuid,
@@ -1425,9 +1263,7 @@ public class XmppConnectionService extends Service {
public void markMessage(Message message, int status) {
message.setStatus(status);
databaseBackend.updateMessage(message);
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
- }
+ updateConversationUi();
}
public SharedPreferences getPreferences() {
@@ -1439,14 +1275,32 @@ public class XmppConnectionService extends Service {
return getPreferences().getBoolean("confirm_messages", true);
}
- public void updateUi(Conversation conversation, boolean notify) {
- if (convChangedListener != null) {
- convChangedListener.onConversationListChanged();
+ 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();
+ }
+ }
+
+ public void updateAccountUi() {
+ if (mOnAccountUpdate != null) {
+ mOnAccountUpdate.onAccountUpdate();
+ }
+ }
+
+ public void updateRosterUi() {
+ if (mOnRosterUpdate != null) {
+ mOnRosterUpdate.onRosterUpdate();
+ }
+ }
public Account findAccountByJid(String accountJid) {
for (Account account : this.accounts) {
@@ -1456,20 +1310,24 @@ public class XmppConnectionService extends Service {
}
return null;
}
-
- public void markRead(Conversation conversation) {
- conversation.markRead(this);
+
+ public Conversation findConversationByUuid(String uuid) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getUuid().equals(uuid)) {
+ return conversation;
+ }
+ }
+ return null;
}
- public void sendConfirmMessage(Account account, String to, String id) {
- MessagePacket receivedPacket = new MessagePacket();
- receivedPacket.setType(MessagePacket.TYPE_NORMAL);
- receivedPacket.setTo(to);
- receivedPacket.setFrom(account.getFullJid());
- Element received = receivedPacket.addChild("displayed",
- "urn:xmpp:chat-markers:0");
- received.setAttribute("id", id);
- account.getXmppConnection().sendMessagePacket(receivedPacket);
+ public void markRead(Conversation conversation) {
+ conversation.markRead();
+ String id = conversation.popLatestMarkableMessageId();
+ if (confirmMessages() && id != null) {
+ Account account = conversation.getAccount();
+ String to = conversation.getContactJid();
+ this.sendMessagePacket(conversation.getAccount(), mMessageGenerator.confirm(account, to, id));
+ }
}
public SecureRandom getRNG() {
@@ -1482,19 +1340,87 @@ public class XmppConnectionService extends Service {
public void replyWithNotAcceptable(Account account, MessagePacket packet) {
if (account.getStatus() == Account.STATUS_ONLINE) {
- MessagePacket error = this.mMessageGenerator.generateNotAcceptable(packet);
- account.getXmppConnection().sendMessagePacket(error);
+ MessagePacket error = this.mMessageGenerator
+ .generateNotAcceptable(packet);
+ sendMessagePacket(account,error);
}
}
-
+
public void syncRosterToDisk(final Account account) {
new Thread(new Runnable() {
-
+
@Override
public void run() {
databaseBackend.writeRoster(account.getRoster());
}
}).start();
-
+
+ }
+
+ public List<String> getKnownHosts() {
+ List<String> hosts = new ArrayList<String>();
+ for (Account account : getAccounts()) {
+ if (!hosts.contains(account.getServer())) {
+ hosts.add(account.getServer());
+ }
+ for (Contact contact : account.getRoster().getContacts()) {
+ if (contact.showInRoster()) {
+ String server = contact.getServer();
+ if (server != null && !hosts.contains(server)) {
+ hosts.add(server);
+ }
+ }
+ }
+ }
+ return hosts;
+ }
+
+ public List<String> getKnownConferenceHosts() {
+ ArrayList<String> mucServers = new ArrayList<String>();
+ for (Account account : accounts) {
+ if (account.getXmppConnection() != null) {
+ String server = account.getXmppConnection().getMucServer();
+ if (server != null) {
+ mucServers.add(server);
+ }
+ }
+ }
+ return mucServers;
+ }
+
+ public void sendMessagePacket(Account account, MessagePacket packet) {
+ account.getXmppConnection().sendMessagePacket(packet);
+ }
+
+ public void sendPresencePacket(Account account, PresencePacket packet) {
+ account.getXmppConnection().sendPresencePacket(packet);
+ }
+
+ public void sendIqPacket(Account account, IqPacket packet, OnIqPacketReceived callback) {
+ account.getXmppConnection().sendIqPacket(packet, callback);
+ }
+
+ public MessageGenerator getMessageGenerator() {
+ return this.mMessageGenerator;
+ }
+
+ public PresenceGenerator getPresenceGenerator() {
+ return this.mPresenceGenerator;
+ }
+
+ public JingleConnectionManager getJingleConnectionManager() {
+ return this.mJingleConnectionManager;
+ }
+
+ public interface OnConversationUpdate {
+ public void onConversationUpdate();
+ }
+
+ public interface OnAccountUpdate {
+ public void onAccountUpdate();
+ }
+
+ public interface OnRosterUpdate {
+ public void onRosterUpdate();
}
}
diff --git a/src/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
new file mode 100644
index 00000000..4236ea70
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/ChooseContactActivity.java
@@ -0,0 +1,140 @@
+package eu.siacs.conversations.ui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.ui.adapter.ListItemAdapter;
+
+public class ChooseContactActivity extends XmppActivity {
+
+ private ListView mListView;
+ private ArrayList<ListItem> contacts = new ArrayList<ListItem>();
+ private ArrayAdapter<ListItem> mContactsAdapter;
+
+ private EditText mSearchEditText;
+
+ private TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ filterContacts(editable.toString());
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ }
+ };
+
+ private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ mSearchEditText.post(new Runnable() {
+
+ @Override
+ public void run() {
+ mSearchEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mSearchEditText,
+ InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+ InputMethodManager.HIDE_IMPLICIT_ONLY);
+ mSearchEditText.setText("");
+ filterContacts(null);
+ return true;
+ }
+ };
+
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_choose_contact);
+ mListView = (ListView) findViewById(R.id.choose_contact_list);
+ mContactsAdapter = new ListItemAdapter(getApplicationContext(), contacts);
+ mListView.setAdapter(mContactsAdapter);
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1, int position,
+ long arg3) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+ InputMethodManager.HIDE_IMPLICIT_ONLY);
+ Intent request = getIntent();
+ Intent data = new Intent();
+ data.putExtra("contact",contacts.get(position).getJid());
+ data.putExtra("account",request.getStringExtra("account"));
+ data.putExtra("conversation",request.getStringExtra("conversation"));
+ setResult(RESULT_OK, data);
+ finish();
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.choose_contact, menu);
+ MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search);
+ View mSearchView = menuSearchView.getActionView();
+ mSearchEditText = (EditText) mSearchView
+ .findViewById(R.id.search_field);
+ mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+ menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+ return true;
+ }
+
+ @Override
+ void onBackendConnected() {
+ filterContacts(null);
+ }
+
+ protected void filterContacts(String needle) {
+ this.contacts.clear();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.getStatus() != Account.STATUS_DISABLED) {
+ for (Contact contact : account.getRoster().getContacts()) {
+ if (contact.showInRoster() && contact.match(needle)) {
+ this.contacts.add(contact);
+ }
+ }
+ }
+ }
+ Collections.sort(this.contacts);
+ mContactsAdapter.notifyDataSetChanged();
+ }
+
+}
diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
new file mode 100644
index 00000000..56903da8
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -0,0 +1,268 @@
+package eu.siacs.conversations.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openintents.openpgp.util.OpenPgpUtils;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.crypto.PgpEngine;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.MucOptions;
+import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
+import eu.siacs.conversations.entities.MucOptions.User;
+import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.IntentSender.SendIntentException;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class ConferenceDetailsActivity extends XmppActivity {
+ public static final String ACTION_VIEW_MUC = "view_muc";
+ private Conversation conversation;
+ private TextView mYourNick;
+ private ImageView mYourPhoto;
+ private ImageButton mEditNickButton;
+ private TextView mRoleAffiliaton;
+ private TextView mFullJid;
+ private LinearLayout membersView;
+ private LinearLayout mMoreDetails;
+ private Button mInviteButton;
+ private String uuid = null;
+
+ private OnClickListener inviteListener = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ inviteToConversation(conversation);
+ }
+ };
+
+ private List<User> users = new ArrayList<MucOptions.User>();
+ private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
+
+ @Override
+ public void onConversationUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_muc_details);
+ mYourNick = (TextView) findViewById(R.id.muc_your_nick);
+ mYourPhoto = (ImageView) findViewById(R.id.your_photo);
+ mEditNickButton = (ImageButton) findViewById(R.id.edit_nick_button);
+ mFullJid = (TextView) findViewById(R.id.muc_jabberid);
+ membersView = (LinearLayout) findViewById(R.id.muc_members);
+ mMoreDetails = (LinearLayout) findViewById(R.id.muc_more_details);
+ mMoreDetails.setVisibility(View.GONE);
+ mInviteButton = (Button) findViewById(R.id.invite);
+ mInviteButton.setOnClickListener(inviteListener);
+ getActionBar().setHomeButtonEnabled(true);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ mEditNickButton.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ quickEdit(conversation.getMucOptions().getActualNick(),
+ new OnValueEdited() {
+
+ @Override
+ public void onValueEdited(String value) {
+ xmppConnectionService.renameInMuc(conversation,
+ value);
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ switch (menuItem.getItemId()) {
+ case android.R.id.home:
+ finish();
+ break;
+ case R.id.action_edit_subject:
+ if (conversation != null) {
+ quickEdit(conversation.getName(true), new OnValueEdited() {
+
+ @Override
+ public void onValueEdited(String value) {
+ MessagePacket packet = xmppConnectionService
+ .getMessageGenerator().conferenceSubject(
+ conversation, value);
+ xmppConnectionService.sendMessagePacket(
+ conversation.getAccount(), packet);
+ }
+ });
+ }
+ break;
+ }
+ return super.onOptionsItemSelected(menuItem);
+ }
+
+ public String getReadableRole(int role) {
+ switch (role) {
+ case User.ROLE_MODERATOR:
+ return getString(R.string.moderator);
+ case User.ROLE_PARTICIPANT:
+ return getString(R.string.participant);
+ case User.ROLE_VISITOR:
+ return getString(R.string.visitor);
+ default:
+ return "";
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.muc_details, menu);
+ return true;
+ }
+
+ @Override
+ void onBackendConnected() {
+ registerListener();
+ if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
+ this.uuid = getIntent().getExtras().getString("uuid");
+ }
+ if (uuid != null) {
+ this.conversation = xmppConnectionService.findConversationByUuid(uuid);
+ if (this.conversation != null) {
+ populateView();
+ }
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService.removeOnConversationListChangedListener();
+ }
+ super.onStop();
+ }
+
+ protected void registerListener() {
+ if (xmppConnectionServiceBound) {
+ xmppConnectionService
+ .setOnConversationListChangedListener(this.onConvChanged);
+ xmppConnectionService.setOnRenameListener(new OnRenameListener() {
+
+ @Override
+ public void onRename(final boolean success) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ if (success) {
+ Toast.makeText(ConferenceDetailsActivity.this,
+ getString(R.string.your_nick_has_been_changed),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(ConferenceDetailsActivity.this,
+ getString(R.string.nick_in_use),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+
+ private void populateView() {
+ mYourPhoto.setImageBitmap(UIHelper.getContactPicture(conversation
+ .getMucOptions().getActualNick(), 48, this, false));
+ setTitle(conversation.getName(true));
+ mFullJid.setText(conversation.getContactJid().split("/")[0]);
+ mYourNick.setText(conversation.getMucOptions().getActualNick());
+ mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
+ if (conversation.getMucOptions().online()) {
+ mMoreDetails.setVisibility(View.VISIBLE);
+ User self = conversation.getMucOptions().getSelf();
+ switch (self.getAffiliation()) {
+ case User.AFFILIATION_ADMIN:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()) + " ("
+ + getString(R.string.admin) + ")");
+ break;
+ case User.AFFILIATION_OWNER:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()) + " ("
+ + getString(R.string.owner) + ")");
+ break;
+ default:
+ mRoleAffiliaton.setText(getReadableRole(self.getRole()));
+ break;
+ }
+ }
+ this.users.clear();
+ this.users.addAll(conversation.getMucOptions().getUsers());
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ membersView.removeAllViews();
+ for (final User contact : conversation.getMucOptions().getUsers()) {
+ View view = (View) inflater.inflate(R.layout.contact, null);
+ TextView displayName = (TextView) view
+ .findViewById(R.id.contact_display_name);
+ TextView key = (TextView) view.findViewById(R.id.key);
+ displayName.setText(contact.getName());
+ TextView role = (TextView) view.findViewById(R.id.contact_jid);
+ role.setText(getReadableRole(contact.getRole()));
+ if (contact.getPgpKeyId() != 0) {
+ key.setVisibility(View.VISIBLE);
+ key.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ viewPgpKey(contact);
+ }
+ });
+ key.setText(OpenPgpUtils.convertKeyIdToHex(contact
+ .getPgpKeyId()));
+ }
+ Bitmap bm = UIHelper.getContactPicture(contact.getName(), 48, this,
+ false);
+ ImageView iv = (ImageView) view.findViewById(R.id.contact_photo);
+ iv.setImageBitmap(bm);
+ membersView.addView(view);
+ }
+ }
+
+ private void viewPgpKey(User user) {
+ PgpEngine pgp = xmppConnectionService.getPgpEngine();
+ if (pgp != null) {
+ PendingIntent intent = pgp.getIntentForKey(
+ conversation.getAccount(), user.getPgpKeyId());
+ if (intent != null) {
+ try {
+ startIntentSenderForResult(intent.getIntentSender(), 0,
+ null, 0, 0, 0);
+ } catch (SendIntentException e) {
+
+ }
+ }
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
index bee93713..71ff4ca8 100644
--- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -21,16 +21,17 @@ import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
-import android.widget.EditText;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import android.widget.Toast;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.utils.UIHelper;
public class ContactDetailsActivity extends XmppActivity {
@@ -39,15 +40,13 @@ public class ContactDetailsActivity extends XmppActivity {
protected ContactDetailsActivity activity = this;
private Contact contact;
-
+
private String accountJid;
private String contactJid;
-
- private EditText name;
+
private TextView contactJidTv;
private TextView accountJidTv;
private TextView status;
- private TextView askAgain;
private TextView lastseen;
private CheckBox send;
private CheckBox receive;
@@ -62,16 +61,6 @@ public class ContactDetailsActivity extends XmppActivity {
}
};
- private DialogInterface.OnClickListener editContactNameListener = new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- contact.setServerName(name.getText().toString());
- activity.xmppConnectionService.pushContactToServer(contact);
- populateView();
- }
- };
-
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
@Override
@@ -91,7 +80,8 @@ public class ContactDetailsActivity extends XmppActivity {
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(getString(R.string.action_add_phone_book));
- builder.setMessage(getString(R.string.add_phone_book_text, contact.getJid()));
+ builder.setMessage(getString(R.string.add_phone_book_text,
+ contact.getJid()));
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setPositiveButton(getString(R.string.add), addToPhonebook);
builder.create().show();
@@ -100,6 +90,60 @@ public class ContactDetailsActivity extends XmppActivity {
private LinearLayout keys;
+ private OnRosterUpdate rosterUpdate = new OnRosterUpdate() {
+
+ @Override
+ public void onRosterUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
+ private OnCheckedChangeListener mOnSendCheckedChange = new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView,
+ boolean isChecked) {
+ if (isChecked) {
+ if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ xmppConnectionService.sendPresencePacket(contact
+ .getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .sendPresenceUpdatesTo(contact));
+ } else {
+ contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
+ }
+ } else {
+ contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .stopPresenceUpdatesTo(contact));
+ }
+ }
+ };
+
+ private OnCheckedChangeListener mOnReceiveCheckedChange = new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView,
+ boolean isChecked) {
+ if (isChecked) {
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .requestPresenceUpdatesFrom(contact));
+ } else {
+ xmppConnectionService.sendPresencePacket(contact.getAccount(),
+ xmppConnectionService.getPresenceGenerator()
+ .stopPresenceUpdatesFrom(contact));
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -114,8 +158,9 @@ public class ContactDetailsActivity extends XmppActivity {
status = (TextView) findViewById(R.id.details_contactstatus);
lastseen = (TextView) findViewById(R.id.details_lastseen);
send = (CheckBox) findViewById(R.id.details_send_presence);
+ send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
receive = (CheckBox) findViewById(R.id.details_receive_presence);
- askAgain = (TextView) findViewById(R.id.ask_again);
+ receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
badge = (QuickContactBadge) findViewById(R.id.details_contact_badge);
keys = (LinearLayout) findViewById(R.id.details_contact_keys);
getActionBar().setHomeButtonEnabled(true);
@@ -136,20 +181,21 @@ public class ContactDetailsActivity extends XmppActivity {
.setMessage(
getString(R.string.remove_contact_text,
contact.getJid()))
- .setPositiveButton(getString(R.string.delete), removeFromRoster).create()
- .show();
+ .setPositiveButton(getString(R.string.delete),
+ removeFromRoster).create().show();
break;
case R.id.action_edit_contact:
if (contact.getSystemAccount() == null) {
+ quickEdit(contact.getDisplayName(), new OnValueEdited() {
- View view = (View) getLayoutInflater().inflate(
- R.layout.edit_contact_name, null);
- name = (EditText) view.findViewById(R.id.editText1);
- name.setText(contact.getDisplayName());
- builder.setView(view).setTitle(contact.getJid())
- .setPositiveButton(getString(R.string.edit), editContactNameListener)
- .create().show();
-
+ @Override
+ public void onValueEdited(String value) {
+ contact.setServerName(value);
+ activity.xmppConnectionService
+ .pushContactToServer(contact);
+ populateView();
+ }
+ });
} else {
Intent intent = new Intent(Intent.ACTION_EDIT);
String[] systemAccount = contact.getSystemAccount().split("#");
@@ -173,39 +219,34 @@ public class ContactDetailsActivity extends XmppActivity {
private void populateView() {
setTitle(contact.getDisplayName());
if (contact.getOption(Contact.Options.FROM)) {
+ send.setText(R.string.send_presence_updates);
send.setChecked(true);
+ } else if (contact
+ .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ send.setChecked(false);
+ send.setText(R.string.send_presence_updates);
} else {
send.setText(R.string.preemptively_grant);
- if (contact
- .getOption(Contact.Options.PREEMPTIVE_GRANT)) {
+ if (contact.getOption(Contact.Options.PREEMPTIVE_GRANT)) {
send.setChecked(true);
} else {
send.setChecked(false);
}
}
if (contact.getOption(Contact.Options.TO)) {
+ receive.setText(R.string.receive_presence_updates);
receive.setChecked(true);
} else {
receive.setText(R.string.ask_for_presence_updates);
- askAgain.setVisibility(View.VISIBLE);
- askAgain.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Toast.makeText(getApplicationContext(), getString(R.string.asked_for_presence_updates),
- Toast.LENGTH_SHORT).show();
- xmppConnectionService.requestPresenceUpdatesFrom(contact);
-
- }
- });
if (contact.getOption(Contact.Options.ASKING)) {
receive.setChecked(true);
} else {
receive.setChecked(false);
}
}
-
- lastseen.setText(UIHelper.lastseen(getApplicationContext(),contact.lastseen.time));
+
+ lastseen.setText(UIHelper.lastseen(getApplicationContext(),
+ contact.lastseen.time));
switch (contact.getMostAvailableStatus()) {
case Presences.CHAT:
@@ -238,13 +279,15 @@ public class ContactDetailsActivity extends XmppActivity {
break;
}
if (contact.getPresences().size() > 1) {
- contactJidTv.setText(contact.getJid()+" ("+contact.getPresences().size()+")");
+ contactJidTv.setText(contact.getJid() + " ("
+ + contact.getPresences().size() + ")");
} else {
contactJidTv.setText(contact.getJid());
}
accountJidTv.setText(contact.getAccount().getJid());
- UIHelper.prepareContactBadge(this, badge, contact, getApplicationContext());
+ UIHelper.prepareContactBadge(this, badge, contact,
+ getApplicationContext());
if (contact.getSystemAccount() == null) {
badge.setOnClickListener(onBadgeClick);
@@ -269,17 +312,20 @@ public class ContactDetailsActivity extends XmppActivity {
keyType.setText("PGP Key ID");
key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
view.setOnClickListener(new OnClickListener() {
-
+
@Override
public void onClick(View v) {
- PgpEngine pgp = activity.xmppConnectionService.getPgpEngine();
- if (pgp!=null) {
+ PgpEngine pgp = activity.xmppConnectionService
+ .getPgpEngine();
+ if (pgp != null) {
PendingIntent intent = pgp.getIntentForKey(contact);
- if (intent!=null) {
+ if (intent != null) {
try {
- startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
+ startIntentSenderForResult(
+ intent.getIntentSender(), 0, null, 0,
+ 0, 0);
} catch (SendIntentException e) {
-
+
}
}
}
@@ -291,9 +337,11 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
public void onBackendConnected() {
- if ((accountJid != null)&&(contactJid != null)) {
- Account account = xmppConnectionService.findAccountByJid(accountJid);
- if (account==null) {
+ xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate);
+ if ((accountJid != null) && (contactJid != null)) {
+ Account account = xmppConnectionService
+ .findAccountByJid(accountJid);
+ if (account == null) {
return;
}
this.contact = account.getRoster().getContact(contactJid);
@@ -304,73 +352,7 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
protected void onStop() {
super.onStop();
- boolean updated = false;
- if (contact!=null) {
- boolean online = contact.getAccount().getStatus() == Account.STATUS_ONLINE;
- if (contact.getOption(Contact.Options.FROM)) {
- if (!send.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.FROM);
- contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
- activity.xmppConnectionService.stopPresenceUpdatesTo(contact);
- }
- updated = true;
- }
- } else {
- if (contact
- .getOption(Contact.Options.PREEMPTIVE_GRANT)) {
- if (!send.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
- }
- updated = true;
- }
- } else {
- if (send.isChecked()) {
- if (online) {
- contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
- }
- updated = true;
- }
- }
- }
- if (contact.getOption(Contact.Options.TO)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.TO);
- activity.xmppConnectionService.stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (contact.getOption(Contact.Options.ASKING)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.ASKING);
- activity.xmppConnectionService
- .stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (receive.isChecked()) {
- if (online) {
- contact.setOption(Contact.Options.ASKING);
- activity.xmppConnectionService
- .requestPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- }
- }
- if (updated) {
- if (online) {
- Toast.makeText(getApplicationContext(), getString(R.string.subscription_updated), Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(getApplicationContext(), getString(R.string.subscription_not_updated_offline), Toast.LENGTH_SHORT).show();
- }
- }
- }
+ xmppConnectionService.removeOnRosterUpdateListener();
}
}
diff --git a/src/eu/siacs/conversations/ui/ContactsActivity.java b/src/eu/siacs/conversations/ui/ContactsActivity.java
deleted file mode 100644
index fee3de7a..00000000
--- a/src/eu/siacs/conversations/ui/ContactsActivity.java
+++ /dev/null
@@ -1,598 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-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.utils.CryptoHelper;
-import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.utils.Validator;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.SparseBooleanArray;
-import android.view.ActionMode;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemLongClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.EditText;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.ImageView;
-import android.widget.Toast;
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-
-public class ContactsActivity extends XmppActivity {
-
- protected List<Contact> rosterContacts = new ArrayList<Contact>();
- protected List<Contact> aggregatedContacts = new ArrayList<Contact>();
- protected ListView contactsView;
- protected ArrayAdapter<Contact> contactsAdapter;
-
- protected EditText search;
- protected String searchString = "";
- private TextView contactsHeader;
- private List<Account> accounts;
- private List<Contact> selectedContacts = new ArrayList<Contact>();
-
- private ContactsActivity activity = this;
-
- private boolean useSubject = true;
- private boolean isActionMode = false;
- private boolean inviteIntent = false;
- private ActionMode actionMode = null;
- private AbsListView.MultiChoiceModeListener actionModeCallback = new AbsListView.MultiChoiceModeListener() {
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- menu.clear();
- MenuInflater inflater = mode.getMenuInflater();
- inflater.inflate(R.menu.newconversation_context, menu);
- SparseBooleanArray checkedItems = contactsView
- .getCheckedItemPositions();
- selectedContacts.clear();
- for (int i = 0; i < aggregatedContacts.size(); ++i) {
- if (checkedItems.get(i, false)) {
- selectedContacts.add(aggregatedContacts.get(i));
- }
- }
- if (selectedContacts.size() == 0) {
- menu.findItem(R.id.action_start_conversation).setVisible(false);
- menu.findItem(R.id.action_contact_details).setVisible(false);
- menu.findItem(R.id.action_invite).setVisible(false);
- menu.findItem(R.id.action_invite_to_existing).setVisible(false);
- } else if ((selectedContacts.size() == 1) && (!inviteIntent)) {
- menu.findItem(R.id.action_start_conversation).setVisible(true);
- menu.findItem(R.id.action_contact_details).setVisible(true);
- menu.findItem(R.id.action_invite).setVisible(false);
- menu.findItem(R.id.action_invite_to_existing).setVisible(true);
- } else if (!inviteIntent) {
- menu.findItem(R.id.action_start_conversation).setVisible(true);
- menu.findItem(R.id.action_contact_details).setVisible(false);
- menu.findItem(R.id.action_invite).setVisible(false);
- menu.findItem(R.id.action_invite_to_existing).setVisible(true);
- } else {
- menu.findItem(R.id.action_invite).setVisible(true);
- menu.findItem(R.id.action_start_conversation).setVisible(false);
- menu.findItem(R.id.action_contact_details).setVisible(false);
- menu.findItem(R.id.action_invite_to_existing).setVisible(false);
- }
- return true;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- return true;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_start_conversation:
- if (selectedContacts.size() == 1) {
- startConversation(selectedContacts.get(0));
- } else {
- startConference();
- }
- break;
- case R.id.action_contact_details:
- Intent intent = new Intent(getApplicationContext(),
- ContactDetailsActivity.class);
- intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
- intent.putExtra("account", selectedContacts.get(0).getAccount().getJid());
- intent.putExtra("contact",selectedContacts.get(0).getJid());
- startActivity(intent);
- finish();
- break;
- case R.id.action_invite:
- invite();
- break;
- case R.id.action_invite_to_existing:
- final List<Conversation> mucs = new ArrayList<Conversation>();
- for(Conversation conv : xmppConnectionService.getConversations()) {
- if (conv.getMode() == Conversation.MODE_MULTI) {
- mucs.add(conv);
- }
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(getString(R.string.invite_contacts_to_existing));
- if (mucs.size() >= 1) {
- String[] options = new String[mucs.size()];
- for(int i = 0; i < options.length; ++i) {
- options[i] = mucs.get(i).getName(useSubject);
- }
- builder.setItems(options, new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Conversation conversation = mucs.get(which);
- if (isOnline(conversation.getAccount())) {
- xmppConnectionService.inviteToConference(conversation, selectedContacts);
- Toast.makeText(activity, getString(R.string.invitation_sent), Toast.LENGTH_SHORT).show();
- actionMode.finish();
- }
- }
- });
- } else {
- builder.setMessage(getString(R.string.no_open_mucs));
- }
- builder.setNegativeButton(getString(R.string.cancel),null);
- builder.create().show();
- break;
- default:
- break;
- }
- return false;
- }
-
- @Override
- public void onItemCheckedStateChanged(ActionMode mode, int position,
- long id, boolean checked) {
- }
- };
-
- private boolean isOnline(Account account) {
- if (account.getStatus() == Account.STATUS_ONLINE) {
- return true;
- } else {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.account_offline));
- builder.setMessage(getString(R.string.cant_invite_while_offline));
- builder.setNegativeButton(getString(R.string.ok), null);
- builder.setIconAttribute(android.R.attr.alertDialogIcon);
- builder.create().show();
- return false;
- }
- }
-
- private void invite() {
- List<Conversation> conversations = xmppConnectionService
- .getConversations();
- Conversation conversation = null;
- for (Conversation tmpConversation : conversations) {
- if (tmpConversation.getUuid().equals(
- getIntent().getStringExtra("uuid"))) {
- conversation = tmpConversation;
- break;
- }
- }
- if (conversation != null) {
- xmppConnectionService.inviteToConference(conversation,
- selectedContacts);
- }
- finish();
- }
-
- private void startConference() {
- if (accounts.size() > 1) {
- getAccountChooser(new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startConference(accounts.get(which));
- }
- }).show();
- } else {
- startConference(accounts.get(0));
- }
-
- }
-
- private void startConference(final Account account) {
- if (isOnline(account)) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.new_conference));
- builder.setMessage(getString(R.string.new_conference_explained));
- builder.setNegativeButton(getString(R.string.cancel), null);
- builder.setPositiveButton(getString(R.string.create_invite),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String mucName = CryptoHelper.randomMucName(xmppConnectionService.getRNG());
- String serverName = account.getXmppConnection()
- .getMucServer();
- if (serverName==null) {
- List<String> servers = getMucServers();
- if (servers.size() >= 1) {
- serverName = servers.get(0);
- } else {
- displayErrorDialog(R.string.no_muc_server_found);
- return;
- }
- }
- String jid = mucName + "@" + serverName;
- Conversation conversation = xmppConnectionService
- .findOrCreateConversation(account, jid, true);
- StringBuilder subject = new StringBuilder();
- subject.append(account.getUsername() + ", ");
- for (int i = 0; i < selectedContacts.size(); ++i) {
- if (i + 1 != selectedContacts.size()) {
- subject.append(selectedContacts.get(i)
- .getDisplayName() + ", ");
- } else {
- subject.append(selectedContacts.get(i)
- .getDisplayName());
- }
- }
- xmppConnectionService.sendConversationSubject(
- conversation, subject.toString());
- xmppConnectionService.inviteToConference(conversation,
- selectedContacts);
- switchToConversation(conversation, null,false);
- }
- });
- builder.create().show();
- }
- }
-
- protected void updateAggregatedContacts() {
-
- aggregatedContacts.clear();
- for (Contact contact : rosterContacts) {
- if (contact.match(searchString)&&(contact.showInRoster()))
- aggregatedContacts.add(contact);
- }
-
- Collections.sort(aggregatedContacts, new Comparator<Contact>() {
-
- @SuppressLint("DefaultLocale")
- @Override
- public int compare(Contact lhs, Contact rhs) {
- return lhs.getDisplayName().toLowerCase()
- .compareTo(rhs.getDisplayName().toLowerCase());
- }
- });
-
- if (aggregatedContacts.size() == 0) {
-
- if (Validator.isValidJid(searchString)) {
- Contact newContact = new Contact(searchString);
- newContact.resetOption(Contact.Options.IN_ROSTER);
- aggregatedContacts.add(newContact);
- contactsHeader.setText(getString(R.string.new_contact));
- } else {
- contactsHeader.setText(getString(R.string.contacts));
- }
- } else {
- contactsHeader.setText(getString(R.string.contacts));
- }
-
- contactsAdapter.notifyDataSetChanged();
- contactsView.setScrollX(0);
- }
-
- private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener() {
-
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int position, long arg3) {
- if (!isActionMode) {
- contactsView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- contactsView.setItemChecked(position, true);
- actionMode = contactsView.startActionMode(actionModeCallback);
- }
- return true;
- }
- };
-
- @Override
- protected void onStart() {
- super.onStart();
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
- this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
- inviteIntent = "invite".equals(getIntent().getAction());
- if (inviteIntent) {
- contactsHeader.setVisibility(View.GONE);
- actionMode = contactsView.startActionMode(actionModeCallback);
- search.setVisibility(View.GONE);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_new_conversation);
-
- contactsHeader = (TextView) findViewById(R.id.contacts_header);
-
- search = (EditText) findViewById(R.id.new_conversation_search);
- search.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- searchString = search.getText().toString();
- updateAggregatedContacts();
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- // TODO Auto-generated method stub
-
- }
- });
-
- contactsView = (ListView) findViewById(R.id.contactList);
- contactsAdapter = new ArrayAdapter<Contact>(getApplicationContext(),
- R.layout.contact, aggregatedContacts) {
- @Override
- public View getView(int position, View view, ViewGroup parent) {
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- Contact contact = getItem(position);
- if (view == null) {
- view = (View) inflater.inflate(R.layout.contact, null);
- }
-
- ((TextView) view.findViewById(R.id.contact_display_name))
- .setText(getItem(position).getDisplayName());
- TextView contactJid = (TextView) view
- .findViewById(R.id.contact_jid);
- contactJid.setText(contact.getJid());
- ImageView imageView = (ImageView) view
- .findViewById(R.id.contact_photo);
- imageView.setImageBitmap(UIHelper.getContactPicture(contact, 48, this.getContext(), false));
- return view;
- }
- };
- contactsView.setAdapter(contactsAdapter);
- contactsView.setMultiChoiceModeListener(actionModeCallback);
- contactsView.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> arg0, final View view,
- int pos, long arg3) {
- if (!isActionMode) {
- Contact clickedContact = aggregatedContacts.get(pos);
- startConversation(clickedContact);
-
- } else {
- actionMode.invalidate();
- }
- }
- });
- contactsView.setOnItemLongClickListener(this.onLongClickListener);
- }
-
- public void startConversation(final Contact contact) {
- if ((contact.getAccount() == null) && (accounts.size() > 1)) {
- getAccountChooser(new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- contact.setAccount(accounts.get(which));
- showIsMucDialogIfNeeded(contact);
- }
- }).show();
- } else {
- if (contact.getAccount() == null) {
- contact.setAccount(accounts.get(0));
- }
- showIsMucDialogIfNeeded(contact);
- }
- }
-
- protected AlertDialog getAccountChooser(OnClickListener listener) {
- String[] accountList = new String[accounts.size()];
- for (int i = 0; i < accounts.size(); ++i) {
- accountList[i] = accounts.get(i).getJid();
- }
-
- AlertDialog.Builder accountChooser = new AlertDialog.Builder(this);
- accountChooser.setTitle(getString(R.string.choose_account));
- accountChooser.setItems(accountList, listener);
- return accountChooser.create();
- }
-
- public void showIsMucDialogIfNeeded(final Contact clickedContact) {
- if (isMuc(clickedContact)) {
- startConversation(clickedContact,clickedContact.getAccount(), true);
- } else if (clickedContact.couldBeMuc()) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setTitle(getString(R.string.multi_user_conference));
- dialog.setMessage(getString(R.string.trying_join_conference));
- dialog.setPositiveButton(getString(R.string.yes), new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startConversation(clickedContact,
- clickedContact.getAccount(), true);
- }
- });
- dialog.setNegativeButton(getString(R.string.no), new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startConversation(clickedContact,
- clickedContact.getAccount(), false);
- }
- });
- dialog.create().show();
- } else {
- startConversation(clickedContact, clickedContact.getAccount(),
- false);
- }
- }
-
- private List<String> getMucServers() {
- ArrayList<String> mucServers = new ArrayList<String>();
- for(Account account : accounts) {
- if (account.getXmppConnection()!=null) {
- String server = account.getXmppConnection().getMucServer();
- if (server!=null) {
- mucServers.add(server);
- }
- }
- }
- return mucServers;
- }
-
- private boolean isMuc(Contact contact) {
- String[] parts = contact.getJid().split("@");
- if (parts.length != 2) {
- return false;
- }
- return getMucServers().contains(parts[1]);
- }
-
- public void startConversation(Contact contact, Account account, boolean muc) {
- if (!contact.getOption(Contact.Options.IN_ROSTER)&&(!muc)) {
- xmppConnectionService.createContact(contact);
- }
- Conversation conversation = xmppConnectionService
- .findOrCreateConversation(account, contact.getJid(), muc);
-
- switchToConversation(conversation, null,false);
- }
-
- @Override
- void onBackendConnected() {
- this.accounts = xmppConnectionService.getAccounts();
- if (Intent.ACTION_SENDTO.equals(getIntent().getAction())) {
- getActionBar().setDisplayHomeAsUpEnabled(false);
- getActionBar().setHomeButtonEnabled(false);
- String jid;
- try {
- jid = URLDecoder.decode(getIntent().getData().getEncodedPath(),
- "UTF-8").split("/")[1];
- } catch (UnsupportedEncodingException e) {
- jid = null;
- }
- if (jid != null) {
- final String finalJid = jid;
- if (this.accounts.size() > 1) {
- getAccountChooser(new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Conversation conversation = xmppConnectionService
- .findOrCreateConversation(
- accounts.get(which), finalJid,
- false);
- switchToConversation(conversation, null,false);
- finish();
- }
- }).show();
- } else {
- Conversation conversation = xmppConnectionService
- .findOrCreateConversation(this.accounts.get(0),
- jid, false);
- switchToConversation(conversation, null,false);
- finish();
- }
- }
- }
-
- if (xmppConnectionService.getConversationCount() == 0) {
- getActionBar().setDisplayHomeAsUpEnabled(false);
- getActionBar().setHomeButtonEnabled(false);
- }
- this.rosterContacts.clear();
- for(Account account : accounts) {
- if (account.getStatus() != Account.STATUS_DISABLED) {
- rosterContacts.addAll(account.getRoster().getContacts());
- }
- }
- updateAggregatedContacts();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.newconversation, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- default:
- break;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onActionModeStarted(ActionMode mode) {
- super.onActionModeStarted(mode);
- this.isActionMode = true;
- search.setEnabled(false);
- }
-
- @Override
- public void onActionModeFinished(ActionMode mode) {
- super.onActionModeFinished(mode);
- if (inviteIntent) {
- finish();
- } else {
- this.isActionMode = false;
- contactsView.clearChoices();
- contactsView.requestLayout();
- contactsView.post(new Runnable() {
- @Override
- public void run() {
- contactsView.setChoiceMode(ListView.CHOICE_MODE_NONE);
- }
- });
- search.setEnabled(true);
- }
- }
-
-}
diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java
index 03ced289..05b7cb4a 100644
--- a/src/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/ConversationActivity.java
@@ -10,6 +10,7 @@ import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.ImageProvider;
+import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.UIHelper;
import android.net.Uri;
@@ -83,10 +84,10 @@ public class ConversationActivity extends XmppActivity {
private boolean showLastseen = false;
private ArrayAdapter<Conversation> listAdapter;
- private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() {
-
+ private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
+
@Override
- public void onConversationListChanged() {
+ public void onConversationUpdate() {
runOnUiThread(new Runnable() {
@Override
@@ -97,7 +98,7 @@ public class ConversationActivity extends XmppActivity {
swapConversationFragment();
} else {
startActivity(new Intent(getApplicationContext(),
- ContactsActivity.class));
+ StartConversationActivity.class));
finish();
}
}
@@ -305,23 +306,26 @@ public class ConversationActivity extends XmppActivity {
.findItem(R.id.action_muc_details);
MenuItem menuContactDetails = (MenuItem) menu
.findItem(R.id.action_contact_details);
- MenuItem menuInviteContacts = (MenuItem) menu
- .findItem(R.id.action_invite);
MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file);
MenuItem menuClearHistory = (MenuItem) menu
.findItem(R.id.action_clear_history);
+ MenuItem menuManageAccounts = (MenuItem) menu.findItem(R.id.action_accounts);
+ MenuItem menuSettings = (MenuItem) menu.findItem(R.id.action_settings);
+ MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
+ MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite);
if ((spl.isOpen() && (spl.isSlideable()))) {
menuArchive.setVisible(false);
menuMucDetails.setVisible(false);
menuContactDetails.setVisible(false);
menuSecure.setVisible(false);
- menuInviteContacts.setVisible(false);
+ menuInviteContact.setVisible(false);
menuAttach.setVisible(false);
menuClearHistory.setVisible(false);
} else {
- ((MenuItem) menu.findItem(R.id.action_add)).setVisible(!spl
- .isSlideable());
+ menuAdd.setVisible(!spl.isSlideable());
+ menuSettings.setVisible(!spl.isSlideable());
+ menuManageAccounts.setVisible(!spl.isSlideable());
if (this.getSelectedConversation() != null) {
if (this.getSelectedConversation().getLatestMessage()
.getEncryption() != Message.ENCRYPTION_NONE) {
@@ -332,7 +336,7 @@ public class ConversationActivity extends XmppActivity {
menuAttach.setVisible(false);
} else {
menuMucDetails.setVisible(false);
- menuInviteContacts.setVisible(false);
+ menuInviteContact.setVisible(false);
}
}
}
@@ -419,37 +423,6 @@ public class ConversationActivity extends XmppActivity {
selectPresenceToAttachFile(attachmentChoice);
} else {
selectPresenceToAttachFile(attachmentChoice);
- /*AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.otr_file_transfer));
- builder.setMessage(getString(R.string.otr_file_transfer_msg));
- builder.setNegativeButton(getString(R.string.cancel), null);
- if (conversation.getContact().getPgpKeyId() == 0) {
- builder.setPositiveButton(getString(R.string.send_unencrypted),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- conversation
- .setNextEncryption(Message.ENCRYPTION_NONE);
- attachFile(attachmentChoice);
- }
- });
- } else {
- builder.setPositiveButton(
- getString(R.string.use_pgp_encryption),
- new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- conversation
- .setNextEncryption(Message.ENCRYPTION_PGP);
- attachFile(attachmentChoice);
- }
- });
- }
- builder.create().show();*/
}
}
@@ -488,7 +461,7 @@ public class ConversationActivity extends XmppActivity {
attachFilePopup.show();
break;
case R.id.action_add:
- startActivity(new Intent(this, ContactsActivity.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
break;
case R.id.action_archive:
this.endConversation(getSelectedConversation());
@@ -496,28 +469,19 @@ public class ConversationActivity extends XmppActivity {
case R.id.action_contact_details:
Contact contact = this.getSelectedConversation().getContact();
if (contact.showInRoster()) {
- Intent intent = new Intent(this, ContactDetailsActivity.class);
- intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
- intent.putExtra("account", this.getSelectedConversation()
- .getAccount().getJid());
- intent.putExtra("contact", contact.getJid());
- startActivity(intent);
+ switchToContactDetails(contact);
} else {
showAddToRosterDialog(getSelectedConversation());
}
break;
case R.id.action_muc_details:
- Intent intent = new Intent(this, MucDetailsActivity.class);
- intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
+ Intent intent = new Intent(this, ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", getSelectedConversation().getUuid());
startActivity(intent);
break;
case R.id.action_invite:
- Intent inviteIntent = new Intent(getApplicationContext(),
- ContactsActivity.class);
- inviteIntent.setAction("invite");
- inviteIntent.putExtra("uuid", getSelectedConversation().getUuid());
- startActivity(inviteIntent);
+ inviteToConversation(getSelectedConversation());
break;
case R.id.action_security:
final Conversation conversation = getSelectedConversation();
@@ -604,7 +568,7 @@ public class ConversationActivity extends XmppActivity {
return super.onOptionsItemSelected(item);
}
- private void endConversation(Conversation conversation) {
+ public void endConversation(Conversation conversation) {
conversation.setStatus(Conversation.STATUS_ARCHIVED);
paneShouldBeOpen = true;
spl.openPane();
@@ -691,7 +655,7 @@ public class ConversationActivity extends XmppActivity {
this.onBackendConnected();
}
if (conversationList.size() >= 1) {
- onConvChanged.onConversationListChanged();
+ onConvChanged.onConversationUpdate();
}
}
@@ -734,7 +698,7 @@ public class ConversationActivity extends XmppActivity {
finish();
} else if (conversationList.size() <= 0) {
// add no history
- startActivity(new Intent(this, ContactsActivity.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
finish();
} else {
spl.openPane();
@@ -768,7 +732,7 @@ public class ConversationActivity extends XmppActivity {
ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
.findFragmentByTag("conversation");
if (selectedFragment != null) {
- selectedFragment.hidePgpPassphraseBox();
+ selectedFragment.hideSnackbar();
}
} else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
attachImageToConversation(getSelectedConversation(),
@@ -841,8 +805,7 @@ public class ConversationActivity extends XmppActivity {
}
public void updateConversationList() {
- conversationList.clear();
- conversationList.addAll(xmppConnectionService.getConversations());
+ xmppConnectionService.populateWithOrderedConversations(conversationList);
listView.invalidateViews();
}
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index 1e703b48..202bab2e 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -8,13 +8,14 @@ import java.util.Set;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
+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;
-import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
import eu.siacs.conversations.services.ImageProvider;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.jingle.JingleConnection;
import android.app.AlertDialog;
@@ -48,6 +49,7 @@ import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
@@ -61,10 +63,16 @@ public class ConversationFragment extends Fragment {
protected Contact contact;
protected BitmapCache mBitmapCache = new BitmapCache();
+ protected int mPrimaryTextColor;
+ protected int mSecondaryTextColor;
+
protected String queuedPqpMessage = null;
private EditText chatMsg;
private String pastedText = null;
+ private RelativeLayout snackbar;
+ private TextView snackbarMessage;
+ private TextView snackbarAction;
protected Bitmap selfBitmap;
@@ -107,20 +115,26 @@ public class ConversationFragment extends Fragment {
}
};
- private LinearLayout pgpInfo;
- private LinearLayout mucError;
- private TextView mucErrorText;
private OnClickListener clickToMuc = new OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
- intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
+ Intent intent = new Intent(getActivity(),
+ ConferenceDetailsActivity.class);
+ intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", conversation.getUuid());
startActivity(intent);
}
};
+ private OnClickListener leaveMuc = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.endConversation(conversation);
+ }
+ };
+
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
@@ -149,10 +163,6 @@ public class ConversationFragment extends Fragment {
private ConversationActivity activity;
- public void hidePgpPassphraseBox() {
- pgpInfo.setVisibility(View.GONE);
- }
-
public void updateChatMsgHint() {
switch (conversation.getNextEncryption()) {
case Message.ENCRYPTION_NONE:
@@ -177,19 +187,29 @@ public class ConversationFragment extends Fragment {
this.inflater = inflater;
+ mPrimaryTextColor = getResources().getColor(R.color.primarytext);
+ mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
+
final View view = inflater.inflate(R.layout.fragment_conversation,
container, false);
chatMsg = (EditText) view.findViewById(R.id.textinput);
+ chatMsg.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (activity.getSlidingPaneLayout().isSlideable()) {
+ activity.getSlidingPaneLayout().closePane();
+ }
+ }
+ });
ImageButton sendButton = (ImageButton) view
.findViewById(R.id.textSendButton);
sendButton.setOnClickListener(this.sendMsgListener);
- pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
- pgpInfo.setOnClickListener(clickToDecryptListener);
- mucError = (LinearLayout) view.findViewById(R.id.muc_error);
- mucError.setOnClickListener(clickToMuc);
- mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
+ snackbar = (RelativeLayout) view.findViewById(R.id.snackbar);
+ snackbarMessage = (TextView) view.findViewById(R.id.snackbar_message);
+ snackbarAction = (TextView) view.findViewById(R.id.snackbar_action);
messagesView = (ListView) view.findViewById(R.id.messages_view);
messagesView.setOnScrollListener(mOnScrollListener);
@@ -264,7 +284,7 @@ public class ConversationFragment extends Fragment {
if (error) {
viewHolder.time.setTextColor(0xFFe92727);
} else {
- viewHolder.time.setTextColor(0xFF8e8e8e);
+ viewHolder.time.setTextColor(mSecondaryTextColor);
}
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
viewHolder.indicator.setVisibility(View.GONE);
@@ -341,7 +361,7 @@ public class ConversationFragment extends Fragment {
} else {
viewHolder.messageBody.setText("");
}
- viewHolder.messageBody.setTextColor(0xff333333);
+ viewHolder.messageBody.setTextColor(mPrimaryTextColor);
viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
viewHolder.messageBody.setTextIsSelectable(true);
}
@@ -644,34 +664,6 @@ public class ConversationFragment extends Fragment {
activity.invalidateOptionsMenu();
}
}
- if (conversation.getMode() == Conversation.MODE_MULTI) {
- activity.xmppConnectionService
- .setOnRenameListener(new OnRenameListener() {
-
- @Override
- public void onRename(final boolean success) {
- activity.xmppConnectionService
- .updateConversation(conversation);
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- if (success) {
- Toast.makeText(
- getActivity(),
- getString(R.string.your_nick_has_been_changed),
- Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(
- getActivity(),
- getString(R.string.nick_in_use),
- Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- });
- }
}
private void decryptMessage(Message message) {
@@ -682,7 +674,8 @@ public class ConversationFragment extends Fragment {
@Override
public void userInputRequried(PendingIntent pi, Message message) {
askForPassphraseIntent = pi.getIntentSender();
- pgpInfo.setVisibility(View.VISIBLE);
+ showSnackbar(R.string.openpgp_messages_found,
+ R.string.decrypt, clickToDecryptListener);
}
@Override
@@ -698,8 +691,6 @@ public class ConversationFragment extends Fragment {
// updateMessages();
}
});
- } else {
- pgpInfo.setVisibility(View.GONE);
}
}
@@ -707,6 +698,7 @@ public class ConversationFragment extends Fragment {
if (getView() == null) {
return;
}
+ hideSnackbar();
ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) {
for (Message message : this.conversation.getMessages()) {
@@ -735,13 +727,15 @@ public class ConversationFragment extends Fragment {
makeFingerprintWarning(conversation.getLatestEncryption());
}
} else {
- if (conversation.getMucOptions().getError() != 0) {
- mucError.setVisibility(View.VISIBLE);
+ if (!conversation.getMucOptions().online()
+ && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
- mucErrorText.setText(getString(R.string.nick_in_use));
+ showSnackbar(R.string.nick_in_use, R.string.edit,
+ clickToMuc);
+ } else if (conversation.getMucOptions().getError() == MucOptions.ERROR_ROOM_NOT_FOUND) {
+ showSnackbar(R.string.conference_not_found,
+ R.string.leave, leaveMuc);
}
- } else {
- mucError.setVisibility(View.GONE);
}
}
getActivity().invalidateOptionsMenu();
@@ -789,35 +783,41 @@ public class ConversationFragment extends Fragment {
}
protected void makeFingerprintWarning(int latestEncryption) {
- final LinearLayout fingerprintWarning = (LinearLayout) getView()
- .findViewById(R.id.new_fingerprint);
Set<String> knownFingerprints = conversation.getContact()
.getOtrFingerprints();
if ((latestEncryption == Message.ENCRYPTION_OTR)
&& (conversation.hasValidOtrSession()
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
.contains(conversation.getOtrFingerprint())))) {
- fingerprintWarning.setVisibility(View.VISIBLE);
- TextView fingerprint = (TextView) getView().findViewById(
- R.id.otr_fingerprint);
- fingerprint.setText(conversation.getOtrFingerprint());
- fingerprintWarning.setOnClickListener(new OnClickListener() {
+ showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
+ new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (conversation.getOtrFingerprint() != null) {
- AlertDialog dialog = UIHelper.getVerifyFingerprintDialog(
- (ConversationActivity) getActivity(), conversation,
- fingerprintWarning);
- dialog.show();
- }
- }
- });
- } else {
- fingerprintWarning.setVisibility(View.GONE);
+ @Override
+ public void onClick(View v) {
+ if (conversation.getOtrFingerprint() != null) {
+ AlertDialog dialog = UIHelper
+ .getVerifyFingerprintDialog(
+ (ConversationActivity) getActivity(),
+ conversation, snackbar);
+ dialog.show();
+ }
+ }
+ });
}
}
+ protected void showSnackbar(int message, int action,
+ OnClickListener clickListener) {
+ snackbar.setVisibility(View.VISIBLE);
+ snackbarMessage.setText(message);
+ snackbarAction.setText(action);
+ snackbarAction.setOnClickListener(clickListener);
+ }
+
+ protected void hideSnackbar() {
+ snackbar.setVisibility(View.GONE);
+ }
+
protected void sendPlainTextMessage(Message message) {
ConversationActivity activity = (ConversationActivity) getActivity();
activity.xmppConnectionService.sendMessage(message);
diff --git a/src/eu/siacs/conversations/ui/EditAccount.java b/src/eu/siacs/conversations/ui/EditAccountDialog.java
index e1bcaeb5..7c135fc1 100644
--- a/src/eu/siacs/conversations/ui/EditAccount.java
+++ b/src/eu/siacs/conversations/ui/EditAccountDialog.java
@@ -1,14 +1,19 @@
package eu.siacs.conversations.ui;
+import java.util.List;
+
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.utils.Validator;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
+import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -16,9 +21,11 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.TextView;
-public class EditAccount extends DialogFragment {
+public class EditAccountDialog extends DialogFragment {
protected Account account;
+
+ protected AutoCompleteTextView mAccountJid;
public void setAccount(Account account) {
this.account = account;
@@ -30,16 +37,28 @@ public class EditAccount extends DialogFragment {
protected EditAccountListener listener = null;
+ private KnownHostsAdapter mKnownHostsAdapter;
+
public void setEditAccountListener(EditAccountListener listener) {
this.listener = listener;
}
+
+ public void setKnownHosts(List<String> hosts, Context context) {
+ this.mKnownHostsAdapter = new KnownHostsAdapter(context, android.R.layout.simple_list_item_1, hosts);
+ if (this.mAccountJid != null) {
+ this.mAccountJid.setAdapter(this.mKnownHostsAdapter);
+ }
+ }
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.edit_account_dialog, null);
- final EditText jidText = (EditText) view.findViewById(R.id.account_jid);
+ mAccountJid = (AutoCompleteTextView) view.findViewById(R.id.account_jid);
+ if (this.mKnownHostsAdapter!=null) {
+ mAccountJid.setAdapter(this.mKnownHostsAdapter);
+ }
final TextView confirmPwDesc = (TextView) view
.findViewById(R.id.account_confirm_password_desc);
@@ -51,7 +70,7 @@ public class EditAccount extends DialogFragment {
.findViewById(R.id.edit_account_register_new);
if (account != null) {
- jidText.setText(account.getJid());
+ mAccountJid.setText(account.getJid());
password.setText(account.getPassword());
if (account.isOptionSet(Account.OPTION_REGISTER)) {
registerAccount.setChecked(true);
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index c52916a2..6fa1ec31 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -5,7 +5,8 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
+import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
+import eu.siacs.conversations.ui.EditAccountDialog.EditAccountListener;
import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
import android.app.Activity;
@@ -31,21 +32,21 @@ import android.widget.ListView;
import android.widget.TextView;
public class ManageAccountActivity extends XmppActivity {
-
+
protected boolean isActionMode = false;
protected ActionMode actionMode;
protected Account selectedAccountForActionMode = null;
protected ManageAccountActivity activity = this;
-
+
protected boolean firstrun = true;
-
+
protected List<Account> accountList = new ArrayList<Account>();
protected ListView accountListView;
protected ArrayAdapter<Account> accountListViewAdapter;
- protected OnAccountListChangedListener accountChanged = new OnAccountListChangedListener() {
+ protected OnAccountUpdate accountChanged = new OnAccountUpdate() {
@Override
- public void onAccountListChangedListener() {
+ public void onAccountUpdate() {
accountList.clear();
accountList.addAll(xmppConnectionService.getAccounts());
runOnUiThread(new Runnable() {
@@ -57,47 +58,55 @@ public class ManageAccountActivity extends XmppActivity {
});
}
};
-
+
protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
-
+
@Override
- public void onTLSExceptionReceived(final String fingerprint, final Account account) {
+ public void onTLSExceptionReceived(final String fingerprint,
+ final Account account) {
activity.runOnUiThread(new Runnable() {
-
+
@Override
public void run() {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ activity);
builder.setTitle(getString(R.string.account_status_error));
builder.setIconAttribute(android.R.attr.alertDialogIcon);
- View view = (View) getLayoutInflater().inflate(R.layout.cert_warning, null);
+ View view = (View) getLayoutInflater().inflate(
+ R.layout.cert_warning, null);
TextView sha = (TextView) view.findViewById(R.id.sha);
TextView hint = (TextView) view.findViewById(R.id.hint);
StringBuilder humanReadableSha = new StringBuilder();
humanReadableSha.append(fingerprint);
- for(int i = 2; i < 59; i += 3) {
- if ((i==14)||(i==29)||(i==44)) {
+ for (int i = 2; i < 59; i += 3) {
+ if ((i == 14) || (i == 29) || (i == 44)) {
humanReadableSha.insert(i, "\n");
} else {
humanReadableSha.insert(i, ":");
}
-
+
}
- hint.setText(getString(R.string.untrusted_cert_hint,account.getServer()));
+ hint.setText(getString(R.string.untrusted_cert_hint,
+ account.getServer()));
sha.setText(humanReadableSha.toString());
builder.setView(view);
- builder.setNegativeButton(getString(R.string.certif_no_trust), null);
- builder.setPositiveButton(getString(R.string.certif_trust), new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- account.setSSLCertFingerprint(fingerprint);
- activity.xmppConnectionService.updateAccount(account);
- }
- });
+ builder.setNegativeButton(
+ getString(R.string.certif_no_trust), null);
+ builder.setPositiveButton(getString(R.string.certif_trust),
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ account.setSSLCertFingerprint(fingerprint);
+ activity.xmppConnectionService
+ .updateAccount(account);
+ }
+ });
builder.create().show();
}
});
-
+
}
};
@@ -124,55 +133,68 @@ public class ManageAccountActivity extends XmppActivity {
.findViewById(R.id.account_status);
switch (account.getStatus()) {
case Account.STATUS_DISABLED:
- statusView.setText(getString(R.string.account_status_disabled));
+ statusView
+ .setText(getString(R.string.account_status_disabled));
statusView.setTextColor(0xFF1da9da);
break;
case Account.STATUS_ONLINE:
- statusView.setText(getString(R.string.account_status_online));
+ statusView
+ .setText(getString(R.string.account_status_online));
statusView.setTextColor(0xFF83b600);
break;
case Account.STATUS_CONNECTING:
- statusView.setText(getString(R.string.account_status_connecting));
+ statusView
+ .setText(getString(R.string.account_status_connecting));
statusView.setTextColor(0xFF1da9da);
break;
case Account.STATUS_OFFLINE:
- statusView.setText(getString(R.string.account_status_offline));
+ statusView
+ .setText(getString(R.string.account_status_offline));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_UNAUTHORIZED:
- statusView.setText(getString(R.string.account_status_unauthorized));
+ statusView
+ .setText(getString(R.string.account_status_unauthorized));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_SERVER_NOT_FOUND:
- statusView.setText(getString(R.string.account_status_not_found));
+ statusView
+ .setText(getString(R.string.account_status_not_found));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_NO_INTERNET:
- statusView.setText(getString(R.string.account_status_no_internet));
+ statusView
+ .setText(getString(R.string.account_status_no_internet));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_SERVER_REQUIRES_TLS:
- statusView.setText(getString(R.string.account_status_requires_tls));
+ statusView
+ .setText(getString(R.string.account_status_requires_tls));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_TLS_ERROR:
- statusView.setText(getString(R.string.account_status_error));
+ statusView
+ .setText(getString(R.string.account_status_error));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_REGISTRATION_FAILED:
- statusView.setText(getString(R.string.account_status_regis_fail));
+ statusView
+ .setText(getString(R.string.account_status_regis_fail));
statusView.setTextColor(0xFFe92727);
break;
case Account.STATUS_REGISTRATION_CONFLICT:
- statusView.setText(getString(R.string.account_status_regis_conflict));
+ statusView
+ .setText(getString(R.string.account_status_regis_conflict));
statusView.setTextColor(0xFFe92727);
break;
- case Account.STATUS_REGISTRATION_SUCCESSFULL:
- statusView.setText(getString(R.string.account_status_regis_success));
+ case Account.STATUS_REGISTRATION_SUCCESSFULL:
+ statusView
+ .setText(getString(R.string.account_status_regis_success));
statusView.setTextColor(0xFF83b600);
break;
case Account.STATUS_REGISTRATION_NOT_SUPPORTED:
- statusView.setText(getString(R.string.account_status_regis_not_sup));
+ statusView
+ .setText(getString(R.string.account_status_regis_not_sup));
statusView.setTextColor(0xFFe92727);
break;
default:
@@ -192,10 +214,14 @@ public class ManageAccountActivity extends XmppActivity {
int position, long arg3) {
if (!isActionMode) {
Account account = accountList.get(position);
- if ((account.getStatus() == Account.STATUS_OFFLINE)||(account.getStatus() == Account.STATUS_TLS_ERROR)) {
- activity.xmppConnectionService.reconnectAccount(accountList.get(position),true);
+ if ((account.getStatus() == Account.STATUS_OFFLINE)
+ || (account.getStatus() == Account.STATUS_TLS_ERROR)) {
+ activity.xmppConnectionService.reconnectAccount(
+ accountList.get(position), true);
} else if (account.getStatus() == Account.STATUS_ONLINE) {
- activity.startActivity(new Intent(activity.getApplicationContext(),ContactsActivity.class));
+ activity.startActivity(new Intent(activity
+ .getApplicationContext(),
+ StartConversationActivity.class));
} else if (account.getStatus() != Account.STATUS_DISABLED) {
editAccount(account);
}
@@ -205,159 +231,242 @@ public class ManageAccountActivity extends XmppActivity {
}
}
});
- accountListView.setOnItemLongClickListener(new OnItemLongClickListener() {
+ accountListView
+ .setOnItemLongClickListener(new OnItemLongClickListener() {
- @Override
- public boolean onItemLongClick(AdapterView<?> arg0, View view,
- int position, long arg3) {
- if (!isActionMode) {
- accountListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- accountListView.setItemChecked(position,true);
- selectedAccountForActionMode = accountList.get(position);
- actionMode = activity.startActionMode((new ActionMode.Callback() {
-
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- if (selectedAccountForActionMode.isOptionSet(Account.OPTION_DISABLED)) {
- menu.findItem(R.id.mgmt_account_enable).setVisible(true);
- menu.findItem(R.id.mgmt_account_disable).setVisible(false);
- } else {
- menu.findItem(R.id.mgmt_account_disable).setVisible(true);
- menu.findItem(R.id.mgmt_account_enable).setVisible(false);
- }
- return true;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- MenuInflater inflater = mode.getMenuInflater();
- inflater.inflate(R.menu.manageaccounts_context, menu);
- return true;
- }
-
- @Override
- public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
- if (item.getItemId()==R.id.mgmt_account_edit) {
- editAccount(selectedAccountForActionMode);
- } else if (item.getItemId()==R.id.mgmt_account_disable) {
- selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, true);
- xmppConnectionService.updateAccount(selectedAccountForActionMode);
- mode.finish();
- } else if (item.getItemId()==R.id.mgmt_account_enable) {
- selectedAccountForActionMode.setOption(Account.OPTION_DISABLED, false);
- xmppConnectionService.updateAccount(selectedAccountForActionMode);
- mode.finish();
- } else if (item.getItemId()==R.id.mgmt_account_delete) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- 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));
- builder.setPositiveButton(getString(R.string.delete), new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- xmppConnectionService.deleteAccount(selectedAccountForActionMode);
- selectedAccountForActionMode = null;
- mode.finish();
- }
- });
- builder.setNegativeButton(getString(R.string.cancel),null);
- builder.create().show();
- } else if (item.getItemId()==R.id.mgmt_account_announce_pgp) {
- if (activity.hasPgp()) {
- mode.finish();
- announcePgp(selectedAccountForActionMode,null);
- } else {
- activity.showInstallPgpDialog();
- }
- } else if (item.getItemId() == R.id.mgmt_otr_key) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle("OTR Fingerprint");
- String fingerprintTxt = selectedAccountForActionMode.getOtrFingerprint(getApplicationContext());
- View view = (View) getLayoutInflater().inflate(R.layout.otr_fingerprint, null);
- if (fingerprintTxt!=null) {
- TextView fingerprint = (TextView) view.findViewById(R.id.otr_fingerprint);
- TextView noFingerprintView = (TextView) view.findViewById(R.id.otr_no_fingerprint);
- fingerprint.setText(fingerprintTxt);
- fingerprint.setVisibility(View.VISIBLE);
- noFingerprintView.setVisibility(View.GONE);
- }
- builder.setView(view);
- builder.setPositiveButton(getString(R.string.done), null);
- builder.create().show();
- } else if (item.getItemId() == R.id.mgmt_account_info) {
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(getString(R.string.account_info));
- if (selectedAccountForActionMode.getStatus() == Account.STATUS_ONLINE) {
- XmppConnection xmpp = selectedAccountForActionMode.getXmppConnection();
- long connectionAge = (SystemClock.elapsedRealtime() - xmpp.lastConnect) / 60000;
- long sessionAge = (SystemClock.elapsedRealtime() - xmpp.lastSessionStarted) / 60000;
- long connectionAgeHours = connectionAge / 60;
- long sessionAgeHours = sessionAge / 60;
- View view = (View) getLayoutInflater().inflate(R.layout.server_info, null);
- TextView connection = (TextView) view.findViewById(R.id.connection);
- TextView session = (TextView) view.findViewById(R.id.session);
- TextView pcks_sent = (TextView) view.findViewById(R.id.pcks_sent);
- TextView pcks_received = (TextView) view.findViewById(R.id.pcks_received);
- TextView carbon = (TextView) view.findViewById(R.id.carbon);
- TextView stream = (TextView) view.findViewById(R.id.stream);
- TextView roster = (TextView) view.findViewById(R.id.roster);
- TextView presences = (TextView) view.findViewById(R.id.number_presences);
- presences.setText(selectedAccountForActionMode.countPresences()+"");
- pcks_received.setText(""+xmpp.getReceivedStanzas());
- pcks_sent.setText(""+xmpp.getSentStanzas());
- if (connectionAgeHours >= 2) {
- connection.setText(connectionAgeHours+" " + getString(R.string.hours));
- } else {
- connection.setText(connectionAge+" " + getString(R.string.mins));
- }
- if (xmpp.hasFeatureStreamManagment()) {
- if (sessionAgeHours >= 2) {
- session.setText(sessionAgeHours+" " + getString(R.string.hours));
- } else {
- session.setText(sessionAge+" " + getString(R.string.mins));
+ @Override
+ public boolean onItemLongClick(AdapterView<?> arg0,
+ View view, int position, long arg3) {
+ if (!isActionMode) {
+ accountListView
+ .setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ accountListView.setItemChecked(position, true);
+ selectedAccountForActionMode = accountList
+ .get(position);
+ actionMode = activity
+ .startActionMode((new ActionMode.Callback() {
+
+ @Override
+ public boolean onPrepareActionMode(
+ ActionMode mode, Menu menu) {
+ if (selectedAccountForActionMode
+ .isOptionSet(Account.OPTION_DISABLED)) {
+ menu.findItem(
+ R.id.mgmt_account_enable)
+ .setVisible(true);
+ menu.findItem(
+ R.id.mgmt_account_disable)
+ .setVisible(false);
+ } else {
+ menu.findItem(
+ R.id.mgmt_account_disable)
+ .setVisible(true);
+ menu.findItem(
+ R.id.mgmt_account_enable)
+ .setVisible(false);
+ }
+ return true;
}
- stream.setText(getString(R.string.yes));
- } else {
- stream.setText(getString(R.string.no));
- session.setText(connection.getText());
- }
- if (xmpp.hasFeaturesCarbon()) {
- carbon.setText(getString(R.string.yes));
- } else {
- carbon.setText(getString(R.string.no));
- }
- if (xmpp.hasFeatureRosterManagment()) {
- roster.setText(getString(R.string.yes));
- } else {
- roster.setText(getString(R.string.no));
- }
- builder.setView(view);
- } else {
- builder.setMessage(getString(R.string.mgmt_account_account_offline));
- }
- builder.setPositiveButton(getString(R.string.hide), null);
- builder.create().show();
- }
+
+ @Override
+ public void onDestroyActionMode(
+ ActionMode mode) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean onCreateActionMode(
+ ActionMode mode, Menu menu) {
+ MenuInflater inflater = mode
+ .getMenuInflater();
+ inflater.inflate(
+ R.menu.manageaccounts_context,
+ menu);
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(
+ final ActionMode mode,
+ MenuItem item) {
+ if (item.getItemId() == R.id.mgmt_account_edit) {
+ editAccount(selectedAccountForActionMode);
+ } else if (item.getItemId() == R.id.mgmt_account_disable) {
+ selectedAccountForActionMode
+ .setOption(
+ Account.OPTION_DISABLED,
+ true);
+ xmppConnectionService
+ .updateAccount(selectedAccountForActionMode);
+ mode.finish();
+ } else if (item.getItemId() == R.id.mgmt_account_enable) {
+ selectedAccountForActionMode
+ .setOption(
+ Account.OPTION_DISABLED,
+ false);
+ xmppConnectionService
+ .updateAccount(selectedAccountForActionMode);
+ mode.finish();
+ } else if (item.getItemId() == R.id.mgmt_account_delete) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ activity);
+ 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));
+ builder.setPositiveButton(
+ getString(R.string.delete),
+ new OnClickListener() {
+
+ @Override
+ public void onClick(
+ DialogInterface dialog,
+ int which) {
+ xmppConnectionService
+ .deleteAccount(selectedAccountForActionMode);
+ selectedAccountForActionMode = null;
+ mode.finish();
+ }
+ });
+ builder.setNegativeButton(
+ getString(R.string.cancel),
+ null);
+ builder.create().show();
+ } else if (item.getItemId() == R.id.mgmt_account_announce_pgp) {
+ if (activity.hasPgp()) {
+ mode.finish();
+ announcePgp(
+ selectedAccountForActionMode,
+ null);
+ } else {
+ activity.showInstallPgpDialog();
+ }
+ } else if (item.getItemId() == R.id.mgmt_otr_key) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ activity);
+ builder.setTitle("OTR Fingerprint");
+ String fingerprintTxt = selectedAccountForActionMode
+ .getOtrFingerprint(getApplicationContext());
+ View view = (View) getLayoutInflater()
+ .inflate(
+ R.layout.otr_fingerprint,
+ null);
+ if (fingerprintTxt != null) {
+ TextView fingerprint = (TextView) view
+ .findViewById(R.id.otr_fingerprint);
+ TextView noFingerprintView = (TextView) view
+ .findViewById(R.id.otr_no_fingerprint);
+ fingerprint
+ .setText(fingerprintTxt);
+ fingerprint
+ .setVisibility(View.VISIBLE);
+ noFingerprintView
+ .setVisibility(View.GONE);
+ }
+ builder.setView(view);
+ builder.setPositiveButton(
+ getString(R.string.done),
+ null);
+ builder.create().show();
+ } else if (item.getItemId() == R.id.mgmt_account_info) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(
+ activity);
+ builder.setTitle(getString(R.string.account_info));
+ if (selectedAccountForActionMode
+ .getStatus() == Account.STATUS_ONLINE) {
+ XmppConnection xmpp = selectedAccountForActionMode
+ .getXmppConnection();
+ long connectionAge = (SystemClock
+ .elapsedRealtime() - xmpp.lastConnect) / 60000;
+ long sessionAge = (SystemClock
+ .elapsedRealtime() - xmpp.lastSessionStarted) / 60000;
+ long connectionAgeHours = connectionAge / 60;
+ long sessionAgeHours = sessionAge / 60;
+ View view = (View) getLayoutInflater()
+ .inflate(
+ R.layout.server_info,
+ null);
+ TextView connection = (TextView) view
+ .findViewById(R.id.connection);
+ TextView session = (TextView) view
+ .findViewById(R.id.session);
+ TextView pcks_sent = (TextView) view
+ .findViewById(R.id.pcks_sent);
+ TextView pcks_received = (TextView) view
+ .findViewById(R.id.pcks_received);
+ TextView carbon = (TextView) view
+ .findViewById(R.id.carbon);
+ TextView stream = (TextView) view
+ .findViewById(R.id.stream);
+ TextView roster = (TextView) view
+ .findViewById(R.id.roster);
+ TextView presences = (TextView) view
+ .findViewById(R.id.number_presences);
+ presences.setText(selectedAccountForActionMode
+ .countPresences()
+ + "");
+ pcks_received.setText(""
+ + xmpp.getReceivedStanzas());
+ pcks_sent.setText(""
+ + xmpp.getSentStanzas());
+ if (connectionAgeHours >= 2) {
+ connection
+ .setText(connectionAgeHours
+ + " "
+ + getString(R.string.hours));
+ } else {
+ connection
+ .setText(connectionAge
+ + " "
+ + getString(R.string.mins));
+ }
+ if (xmpp.hasFeatureStreamManagment()) {
+ if (sessionAgeHours >= 2) {
+ session.setText(sessionAgeHours
+ + " "
+ + getString(R.string.hours));
+ } else {
+ session.setText(sessionAge
+ + " "
+ + getString(R.string.mins));
+ }
+ stream.setText(getString(R.string.yes));
+ } else {
+ stream.setText(getString(R.string.no));
+ session.setText(connection
+ .getText());
+ }
+ if (xmpp.hasFeaturesCarbon()) {
+ carbon.setText(getString(R.string.yes));
+ } else {
+ carbon.setText(getString(R.string.no));
+ }
+ if (xmpp.hasFeatureRosterManagment()) {
+ roster.setText(getString(R.string.yes));
+ } else {
+ roster.setText(getString(R.string.no));
+ }
+ builder.setView(view);
+ } else {
+ builder.setMessage(getString(R.string.mgmt_account_account_offline));
+ }
+ builder.setPositiveButton(
+ getString(R.string.hide),
+ null);
+ builder.create().show();
+ }
+ return true;
+ }
+
+ }));
return true;
+ } else {
+ return false;
}
-
-
- }));
- return true;
- } else {
- return false;
- }
- }
- });
+ }
+ });
}
-
+
@Override
protected void onStop() {
if (xmppConnectionServiceBound) {
@@ -370,11 +479,12 @@ public class ManageAccountActivity extends XmppActivity {
@Override
void onBackendConnected() {
xmppConnectionService.setOnAccountListChangedListener(accountChanged);
- xmppConnectionService.setOnTLSExceptionReceivedListener(tlsExceptionReceived);
+ xmppConnectionService
+ .setOnTLSExceptionReceivedListener(tlsExceptionReceived);
this.accountList.clear();
this.accountList.addAll(xmppConnectionService.getAccounts());
accountListViewAdapter.notifyDataSetChanged();
- if ((this.accountList.size() == 0)&&(this.firstrun)) {
+ if ((this.accountList.size() == 0) && (this.firstrun)) {
getActionBar().setDisplayHomeAsUpEnabled(false);
getActionBar().setHomeButtonEnabled(false);
addAccount();
@@ -403,14 +513,15 @@ public class ManageAccountActivity extends XmppActivity {
@Override
public boolean onNavigateUp() {
if (xmppConnectionService.getConversations().size() == 0) {
- Intent contactsIntent = new Intent(this, ContactsActivity.class);
+ Intent contactsIntent = new Intent(this, StartConversationActivity.class);
contactsIntent.setFlags(
- // if activity exists in stack, pop the stack and go back to it
+ // if activity exists in stack, pop the stack and go back to it
Intent.FLAG_ACTIVITY_CLEAR_TOP |
// otherwise, make a new task for it
- Intent.FLAG_ACTIVITY_NEW_TASK |
- // don't use the new activity animation; finish animation runs instead
- Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ Intent.FLAG_ACTIVITY_NEW_TASK |
+ // don't use the new activity animation; finish
+ // animation runs instead
+ Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(contactsIntent);
finish();
return true;
@@ -420,25 +531,26 @@ public class ManageAccountActivity extends XmppActivity {
}
private void editAccount(Account account) {
- EditAccount dialog = new EditAccount();
- dialog.setAccount(account);
- dialog.setEditAccountListener(new EditAccountListener() {
+ EditAccountDialog dialog = new EditAccountDialog();
+ dialog.setAccount(account);
+ dialog.setEditAccountListener(new EditAccountListener() {
- @Override
- public void onAccountEdited(Account account) {
- xmppConnectionService.updateAccount(account);
- if (actionMode != null) {
- actionMode.finish();
- }
+ @Override
+ public void onAccountEdited(Account account) {
+ xmppConnectionService.updateAccount(account);
+ if (actionMode != null) {
+ actionMode.finish();
}
- });
- dialog.show(getFragmentManager(), "edit_account");
-
+ }
+ });
+ dialog.show(getFragmentManager(), "edit_account");
+ dialog.setKnownHosts(xmppConnectionService.getKnownHosts(), this);
+
}
-
+
protected void addAccount() {
final Activity activity = this;
- EditAccount dialog = new EditAccount();
+ EditAccountDialog dialog = new EditAccountDialog();
dialog.setEditAccountListener(new EditAccountListener() {
@Override
@@ -449,15 +561,15 @@ public class ManageAccountActivity extends XmppActivity {
}
});
dialog.show(getFragmentManager(), "add_account");
+ dialog.setKnownHosts(xmppConnectionService.getKnownHosts(), this);
}
-
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
this.isActionMode = true;
}
-
+
@Override
public void onActionModeFinished(ActionMode mode) {
super.onActionModeFinished(mode);
@@ -465,20 +577,20 @@ public class ManageAccountActivity extends XmppActivity {
accountListView.clearChoices();
accountListView.requestLayout();
accountListView.post(new Runnable() {
- @Override
- public void run() {
- accountListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
- }
- });
+ @Override
+ public void run() {
+ accountListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
+ }
+ });
}
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (resultCode == RESULT_OK) {
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK) {
if (requestCode == REQUEST_ANNOUNCE_PGP) {
- announcePgp(selectedAccountForActionMode,null);
+ announcePgp(selectedAccountForActionMode, null);
}
- }
- }
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/ui/MucDetailsActivity.java b/src/eu/siacs/conversations/ui/MucDetailsActivity.java
deleted file mode 100644
index ee6709b7..00000000
--- a/src/eu/siacs/conversations/ui/MucDetailsActivity.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package eu.siacs.conversations.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.openintents.openpgp.util.OpenPgpUtils;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.MucOptions;
-import eu.siacs.conversations.entities.MucOptions.User;
-import eu.siacs.conversations.utils.UIHelper;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.IntentSender.SendIntentException;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class MucDetailsActivity extends XmppActivity {
- public static final String ACTION_VIEW_MUC = "view_muc";
- private Conversation conversation;
- private EditText mYourNick;
- private EditText mSubject;
- private TextView mRoleAffiliaton;
- private TextView mFullJid;
- private LinearLayout membersView;
- private LinearLayout mMoreDetails;
- private Button mInviteButton;
- private String uuid = null;
- private OnClickListener changeNickListener = new OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- MucOptions options = conversation.getMucOptions();
- String nick = mYourNick.getText().toString();
- if (!options.getNick().equals(nick)) {
- xmppConnectionService.renameInMuc(conversation, nick);
- finish();
- }
- }
- };
-
- private OnClickListener changeSubjectListener = new OnClickListener() {
-
- @Override
- public void onClick(View arg0) {
- String subject = mSubject.getText().toString();
- MucOptions options = conversation.getMucOptions();
- if (!subject.equals(options.getSubject())) {
- xmppConnectionService.sendConversationSubject(conversation,subject);
- finish();
- }
- }
- };
-
- private OnClickListener inviteListener = new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(getApplicationContext(),
- ContactsActivity.class);
- intent.setAction("invite");
- intent.putExtra("uuid",conversation.getUuid());
- startActivity(intent);
- }
- };
-
- private List<User> users = new ArrayList<MucOptions.User>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_muc_details);
- mYourNick = (EditText) findViewById(R.id.muc_your_nick);
- mFullJid = (TextView) findViewById(R.id.muc_jabberid);
- ImageButton editNickButton = (ImageButton) findViewById(R.id.muc_edit_nick);
- editNickButton.setOnClickListener(this.changeNickListener);
- ImageButton editSubjectButton = (ImageButton) findViewById(R.id.muc_edit_subject);
- editSubjectButton.setOnClickListener(this.changeSubjectListener);
- membersView = (LinearLayout) findViewById(R.id.muc_members);
- mMoreDetails = (LinearLayout) findViewById(R.id.muc_more_details);
- mMoreDetails.setVisibility(View.GONE);
- mSubject = (EditText) findViewById(R.id.muc_subject);
- mInviteButton = (Button) findViewById(R.id.invite);
- mInviteButton.setOnClickListener(inviteListener);
- getActionBar().setHomeButtonEnabled(true);
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- switch (menuItem.getItemId()) {
- case android.R.id.home:
- finish();
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- public String getReadableRole(int role) {
- switch (role) {
- case User.ROLE_MODERATOR:
- return getString(R.string.moderator);
- case User.ROLE_PARTICIPANT:
- return getString(R.string.participant);
- case User.ROLE_VISITOR:
- return getString(R.string.visitor);
- default:
- return "";
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.muc_details, menu);
- return true;
- }
-
- @Override
- void onBackendConnected() {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- boolean useSubject = preferences.getBoolean("use_subject_in_muc", true);
- if (getIntent().getAction().equals(ACTION_VIEW_MUC)) {
- this.uuid = getIntent().getExtras().getString("uuid");
- }
- if (uuid != null) {
- for (Conversation mConv : xmppConnectionService.getConversations()) {
- if (mConv.getUuid().equals(uuid)) {
- this.conversation = mConv;
- }
- }
- if (this.conversation != null) {
- mSubject.setText(conversation.getMucOptions().getSubject());
- setTitle(conversation.getName(useSubject));
- mFullJid.setText(conversation.getContactJid().split("/")[0]);
- mYourNick.setText(conversation.getMucOptions().getNick());
- mRoleAffiliaton = (TextView) findViewById(R.id.muc_role);
- if (conversation.getMucOptions().online()) {
- mMoreDetails.setVisibility(View.VISIBLE);
- User self = conversation.getMucOptions().getSelf();
- switch (self.getAffiliation()) {
- case User.AFFILIATION_ADMIN:
- mRoleAffiliaton.setText(getReadableRole(self.getRole())
- + " (" + getString(R.string.admin) + ")");
- break;
- case User.AFFILIATION_OWNER:
- mRoleAffiliaton.setText(getReadableRole(self.getRole())
- + " (" + getString(R.string.owner) + ")");
- break;
- default:
- mRoleAffiliaton
- .setText(getReadableRole(self.getRole()));
- break;
- }
- }
- this.users.clear();
- this.users.addAll(conversation.getMucOptions().getUsers());
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- membersView.removeAllViews();
- for(final User contact : conversation.getMucOptions().getUsers()) {
- View view = (View) inflater.inflate(R.layout.contact, null);
- TextView displayName = (TextView) view.findViewById(R.id.contact_display_name);
- TextView key = (TextView) view.findViewById(R.id.key);
- displayName.setText(contact.getName());
- TextView role = (TextView) view.findViewById(R.id.contact_jid);
- role.setText(getReadableRole(contact.getRole()));
- if (contact.getPgpKeyId()!=0) {
- key.setVisibility(View.VISIBLE);
- key.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- PgpEngine pgp = xmppConnectionService.getPgpEngine();
- if (pgp!=null) {
- PendingIntent intent = pgp.getIntentForKey(conversation.getAccount(), contact.getPgpKeyId());
- if (intent!=null) {
- try {
- startIntentSenderForResult(intent.getIntentSender(), 0, null, 0, 0, 0);
- } catch (SendIntentException e) {
-
- }
- }
- }
- }
- });
- key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
- }
- ImageView imageView = (ImageView) view
- .findViewById(R.id.contact_photo);
- imageView.setImageBitmap(UIHelper.getContactPicture(contact.getName(), 48,this.getApplicationContext(), false));
- membersView.addView(view);
- }
- }
- } else {
- Log.d("xmppService","uuid in muc details was null");
- }
- }
-}
diff --git a/src/eu/siacs/conversations/ui/OnAccountListChangedListener.java b/src/eu/siacs/conversations/ui/OnAccountListChangedListener.java
deleted file mode 100644
index 98ef445e..00000000
--- a/src/eu/siacs/conversations/ui/OnAccountListChangedListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package eu.siacs.conversations.ui;
-
-public interface OnAccountListChangedListener {
- public void onAccountListChangedListener();
-}
diff --git a/src/eu/siacs/conversations/ui/OnConversationListChangedListener.java b/src/eu/siacs/conversations/ui/OnConversationListChangedListener.java
deleted file mode 100644
index 2a922e21..00000000
--- a/src/eu/siacs/conversations/ui/OnConversationListChangedListener.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package eu.siacs.conversations.ui;
-
-public interface OnConversationListChangedListener {
- public void onConversationListChanged();
-}
diff --git a/src/eu/siacs/conversations/ui/OnPresenceSelected.java b/src/eu/siacs/conversations/ui/OnPresenceSelected.java
deleted file mode 100644
index 1c967224..00000000
--- a/src/eu/siacs/conversations/ui/OnPresenceSelected.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package eu.siacs.conversations.ui;
-
-public interface OnPresenceSelected {
- public void onPresenceSelected();
-}
diff --git a/src/eu/siacs/conversations/ui/ShareWithActivity.java b/src/eu/siacs/conversations/ui/ShareWithActivity.java
index 9fe5e500..461aaec4 100644
--- a/src/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -20,7 +20,6 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
-import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
@@ -90,7 +89,8 @@ public class ShareWithActivity extends XmppActivity {
Set<Contact> displayedContacts = new HashSet<Contact>();
conversations.removeAllViews();
- List<Conversation> convList = xmppConnectionService.getConversations();
+ List<Conversation> convList = new ArrayList<Conversation>();
+ xmppConnectionService.populateWithOrderedConversations(convList);
Collections.sort(convList, new Comparator<Conversation>() {
@Override
public int compare(Conversation lhs, Conversation rhs) {
diff --git a/src/eu/siacs/conversations/ui/StartConversationActivity.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java
new file mode 100644
index 00000000..d12d2878
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -0,0 +1,584 @@
+package eu.siacs.conversations.ui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.app.ListFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.Spinner;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.ListItem;
+import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
+import eu.siacs.conversations.ui.adapter.ListItemAdapter;
+import eu.siacs.conversations.utils.Validator;
+
+public class StartConversationActivity extends XmppActivity {
+
+ private Tab mContactsTab;
+ private Tab mConferencesTab;
+ private ViewPager mViewPager;
+
+ private MyListFragment mContactsListFragment = new MyListFragment();
+ private List<ListItem> contacts = new ArrayList<ListItem>();
+ private ArrayAdapter<ListItem> mContactsAdapter;
+
+ private MyListFragment mConferenceListFragment = new MyListFragment();
+ private List<ListItem> conferences = new ArrayList<ListItem>();
+ private ArrayAdapter<ListItem> mConferenceAdapter;
+
+ private List<String> mActivatedAccounts = new ArrayList<String>();
+ private List<String> mKnownHosts;
+ private List<String> mKnownConferenceHosts;
+
+ private EditText mSearchEditText;
+
+ public int conference_context_id;
+ public int contact_context_id;
+
+ private TabListener mTabListener = new TabListener() {
+
+ @Override
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+ return;
+ }
+
+ @Override
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ mViewPager.setCurrentItem(tab.getPosition());
+ onTabChanged();
+ }
+
+ @Override
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ return;
+ }
+ };
+
+ private ViewPager.SimpleOnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ getActionBar().setSelectedNavigationItem(position);
+ onTabChanged();
+ }
+ };
+
+ private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ mSearchEditText.post(new Runnable() {
+
+ @Override
+ public void run() {
+ mSearchEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mSearchEditText,
+ InputMethodManager.SHOW_IMPLICIT);
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
+ InputMethodManager.HIDE_IMPLICIT_ONLY);
+ mSearchEditText.setText("");
+ filter(null);
+ return true;
+ }
+ };
+ private TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ filter(editable.toString());
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ }
+ };
+ private OnRosterUpdate onRosterUpdate = new OnRosterUpdate() {
+
+ @Override
+ public void onRosterUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_start_conversation);
+ mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager);
+ ActionBar actionBar = getActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+ mContactsTab = actionBar.newTab().setText(R.string.contacts)
+ .setTabListener(mTabListener);
+ mConferencesTab = actionBar.newTab().setText(R.string.conferences)
+ .setTabListener(mTabListener);
+ actionBar.addTab(mContactsTab);
+ actionBar.addTab(mConferencesTab);
+
+ mViewPager.setOnPageChangeListener(mOnPageChangeListener);
+ mViewPager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ if (position == 0) {
+ return mContactsListFragment;
+ } else {
+ return mConferenceListFragment;
+ }
+ }
+ });
+
+ mConferenceAdapter = new ListItemAdapter(getApplicationContext(),conferences);
+ mConferenceListFragment.setListAdapter(mConferenceAdapter);
+ mConferenceListFragment.setContextMenu(R.menu.conference_context);
+ mConferenceListFragment
+ .setOnListItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ openConversationForBookmark(position);
+ }
+ });
+
+ mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
+ mContactsListFragment.setListAdapter(mContactsAdapter);
+ mContactsListFragment.setContextMenu(R.menu.contact_context);
+ mContactsListFragment
+ .setOnListItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ openConversationForContact(position);
+ }
+ });
+
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ xmppConnectionService.removeOnRosterUpdateListener();
+ }
+
+ protected void openConversationForContact(int position) {
+ Contact contact = (Contact) contacts.get(position);
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(contact.getAccount(),
+ contact.getJid(), false);
+ switchToConversation(conversation);
+ }
+
+ protected void openConversationForContact() {
+ int position = contact_context_id;
+ openConversationForContact(position);
+ }
+
+ protected void openConversationForBookmark() {
+ openConversationForBookmark(conference_context_id);
+ }
+
+ protected void openConversationForBookmark(int position) {
+ Bookmark bookmark = (Bookmark) conferences.get(position);
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(bookmark.getAccount(),
+ bookmark.getJid(), true);
+ conversation.setBookmark(bookmark);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
+ if (!bookmark.autojoin()) {
+ bookmark.setAutojoin(true);
+ xmppConnectionService.pushBookmarks(bookmark.getAccount());
+ }
+ switchToConversation(conversation);
+ }
+
+ protected void openDetailsForContact() {
+ int position = contact_context_id;
+ Contact contact = (Contact) contacts.get(position);
+ switchToContactDetails(contact);
+ }
+
+ protected void deleteContact() {
+ int position = contact_context_id;
+ final Contact contact = (Contact) contacts.get(position);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setTitle(R.string.action_delete_contact);
+ builder.setMessage(
+ getString(R.string.remove_contact_text,
+ contact.getJid()));
+ builder.setPositiveButton(R.string.delete,new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ xmppConnectionService.deleteContactOnServer(contact);
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ builder.create().show();
+
+ }
+
+ protected void deleteConference() {
+ int position = conference_context_id;
+ final Bookmark bookmark = (Bookmark) conferences.get(position);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setTitle(R.string.delete_bookmark);
+ builder.setMessage(
+ getString(R.string.remove_bookmark_text,
+ bookmark.getJid()));
+ builder.setPositiveButton(R.string.delete,new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ bookmark.unregisterConversation();
+ Account account = bookmark.getAccount();
+ account.getBookmarks().remove(bookmark);
+ xmppConnectionService.pushBookmarks(account);
+ filter(mSearchEditText.getText().toString());
+ }
+ });
+ builder.create().show();
+
+ }
+
+ protected void showCreateContactDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.create_contact);
+ View dialogView = getLayoutInflater().inflate(
+ R.layout.create_contact_dialog, null);
+ final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
+ final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
+ .findViewById(R.id.jid);
+ jid.setAdapter(new KnownHostsAdapter(this,
+ android.R.layout.simple_list_item_1, mKnownHosts));
+ populateAccountSpinner(spinner);
+ builder.setView(dialogView);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.create, null);
+ final AlertDialog dialog = builder.create();
+ dialog.show();
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
+ new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (Validator.isValidJid(jid.getText().toString())) {
+ String accountJid = (String) spinner
+ .getSelectedItem();
+ String contactJid = jid.getText().toString();
+ Account account = xmppConnectionService
+ .findAccountByJid(accountJid);
+ Contact contact = account.getRoster().getContact(
+ contactJid);
+ if (contact.showInRoster()) {
+ jid.setError(getString(R.string.contact_already_exists));
+ } else {
+ xmppConnectionService.createContact(contact);
+ switchToConversation(contact);
+ dialog.dismiss();
+ }
+ } else {
+ jid.setError(getString(R.string.invalid_jid));
+ }
+ }
+ });
+
+ }
+
+ protected void showJoinConferenceDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.join_conference);
+ View dialogView = getLayoutInflater().inflate(
+ R.layout.join_conference_dialog, null);
+ final Spinner spinner = (Spinner) dialogView.findViewById(R.id.account);
+ final AutoCompleteTextView jid = (AutoCompleteTextView) dialogView
+ .findViewById(R.id.jid);
+ jid.setAdapter(new KnownHostsAdapter(this,
+ android.R.layout.simple_list_item_1, mKnownConferenceHosts));
+ populateAccountSpinner(spinner);
+ final CheckBox bookmarkCheckBox = (CheckBox) dialogView
+ .findViewById(R.id.bookmark);
+ builder.setView(dialogView);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.join, null);
+ final AlertDialog dialog = builder.create();
+ dialog.show();
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
+ new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (Validator.isValidJid(jid.getText().toString())) {
+ String accountJid = (String) spinner
+ .getSelectedItem();
+ String conferenceJid = jid.getText().toString();
+ Account account = xmppConnectionService
+ .findAccountByJid(accountJid);
+ if (bookmarkCheckBox.isChecked()) {
+ if (account.hasBookmarkFor(conferenceJid)) {
+ jid.setError(getString(R.string.bookmark_already_exists));
+ } else {
+ Bookmark bookmark = new Bookmark(account,
+ conferenceJid);
+ bookmark.setAutojoin(true);
+ account.getBookmarks().add(bookmark);
+ xmppConnectionService
+ .pushBookmarks(account);
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(account,
+ conferenceJid, true);
+ conversation.setBookmark(bookmark);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
+ switchToConversation(conversation);
+ }
+ } else {
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(account,
+ conferenceJid, true);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
+ switchToConversation(conversation);
+ }
+ } else {
+ jid.setError(getString(R.string.invalid_jid));
+ }
+ }
+ });
+ }
+
+ protected void switchToConversation(Contact contact) {
+ Conversation conversation = xmppConnectionService
+ .findOrCreateConversation(contact.getAccount(),
+ contact.getJid(), false);
+ switchToConversation(conversation);
+ }
+
+ private void populateAccountSpinner(Spinner spinner) {
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_spinner_item, mActivatedAccounts);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.start_conversation, menu);
+ MenuItem menuCreateContact = (MenuItem) menu
+ .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();
+ mSearchEditText = (EditText) mSearchView
+ .findViewById(R.id.search_field);
+ mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+ if (getActionBar().getSelectedNavigationIndex() == 0) {
+ menuCreateConference.setVisible(false);
+ } else {
+ menuCreateContact.setVisible(false);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_create_contact:
+ showCreateContactDialog();
+ break;
+ case R.id.action_join_conference:
+ showJoinConferenceDialog();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ 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) {
+ this.mActivatedAccounts.add(account.getJid());
+ }
+ }
+ this.mKnownHosts = xmppConnectionService.getKnownHosts();
+ this.mKnownConferenceHosts = xmppConnectionService
+ .getKnownConferenceHosts();
+ }
+
+ protected void filter(String needle) {
+ this.filterContacts(needle);
+ this.filterConferences(needle);
+ }
+
+ protected void filterContacts(String needle) {
+ this.contacts.clear();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.getStatus() != Account.STATUS_DISABLED) {
+ for (Contact contact : account.getRoster().getContacts()) {
+ if (contact.showInRoster() && contact.match(needle)) {
+ this.contacts.add(contact);
+ }
+ }
+ }
+ }
+ Collections.sort(this.contacts);
+ mContactsAdapter.notifyDataSetChanged();
+ }
+
+ protected void filterConferences(String needle) {
+ this.conferences.clear();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.getStatus() != Account.STATUS_DISABLED) {
+ for (Bookmark bookmark : account.getBookmarks()) {
+ if (bookmark.match(needle)) {
+ this.conferences.add(bookmark);
+ }
+ }
+ }
+ }
+ Collections.sort(this.conferences);
+ mConferenceAdapter.notifyDataSetChanged();
+ }
+
+ private void onTabChanged() {
+ invalidateOptionsMenu();
+ }
+
+ public static class MyListFragment extends ListFragment {
+ private AdapterView.OnItemClickListener mOnItemClickListener;
+ private int mResContextMenu;
+
+ public void setContextMenu(int res) {
+ this.mResContextMenu = res;
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ if (mOnItemClickListener != null) {
+ mOnItemClickListener.onItemClick(l, v, position, id);
+ }
+ }
+
+ public void setOnListItemClickListener(AdapterView.OnItemClickListener l) {
+ this.mOnItemClickListener = l;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ registerForContextMenu(getListView());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ StartConversationActivity activity = (StartConversationActivity) getActivity();
+ activity.getMenuInflater().inflate(mResContextMenu, menu);
+ AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
+ if (mResContextMenu == R.menu.conference_context) {
+ activity.conference_context_id = acmi.position;
+ } else {
+ activity.contact_context_id = acmi.position;
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ StartConversationActivity activity = (StartConversationActivity) getActivity();
+ switch (item.getItemId()) {
+ case R.id.context_start_conversation:
+ activity.openConversationForContact();
+ break;
+ case R.id.context_contact_details:
+ activity.openDetailsForContact();
+ break;
+ case R.id.context_delete_contact:
+ activity.deleteContact();
+ break;
+ case R.id.context_join_conference:
+ activity.openConversationForBookmark();
+ break;
+ case R.id.context_delete_conference:
+ activity.deleteConference();
+ }
+ return true;
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index c95cbfec..2bf7cf5a 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -27,16 +27,26 @@ import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
public abstract class XmppActivity extends Activity {
public static final int REQUEST_ANNOUNCE_PGP = 0x73731;
+ protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x341830;
protected final static String LOGTAG = "xmppService";
public XmppConnectionService xmppConnectionService;
public boolean xmppConnectionServiceBound = false;
protected boolean handledViewIntent = false;
+
+ protected interface OnValueEdited {
+ public void onValueEdited(String value);
+ }
+
+ public interface OnPresenceSelected {
+ public void onPresenceSelected();
+ }
protected ServiceConnection mConnection = new ServiceConnection() {
@@ -149,6 +159,10 @@ public abstract class XmppActivity extends Activity {
ExceptionHelper.init(getApplicationContext());
}
+ public void switchToConversation(Conversation conversation) {
+ switchToConversation(conversation, null, false);
+ }
+
public void switchToConversation(Conversation conversation, String text,
boolean newTask) {
Intent viewConversationIntent = new Intent(this,
@@ -171,6 +185,20 @@ public abstract class XmppActivity extends Activity {
startActivity(viewConversationIntent);
}
+ public void switchToContactDetails(Contact contact) {
+ Intent intent = new Intent(this, ContactDetailsActivity.class);
+ intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT);
+ intent.putExtra("account", contact.getAccount().getJid());
+ intent.putExtra("contact", contact.getJid());
+ startActivity(intent);
+ }
+
+ protected void inviteToConversation(Conversation conversation) {
+ Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
+ intent.putExtra("conversation",conversation.getUuid());
+ startActivityForResult(intent, REQUEST_INVITE_TO_CONVERSATION);
+ }
+
protected void announcePgp(Account account, final Conversation conversation) {
xmppConnectionService.getPgpEngine().generateSignature(account,
"online", new UiCallback<Account>() {
@@ -181,17 +209,16 @@ public abstract class XmppActivity extends Activity {
try {
startIntentSenderForResult(pi.getIntentSender(),
REQUEST_ANNOUNCE_PGP, null, 0, 0, 0);
- } catch (SendIntentException e) {
- Log.d("xmppService",
- "coulnd start intent for pgp anncouncment");
- }
+ } catch (SendIntentException e) {}
}
@Override
public void success(Account account) {
xmppConnectionService.databaseBackend
.updateAccount(account);
- xmppConnectionService.sendPresence(account);
+ xmppConnectionService.sendPresencePacket(account,
+ xmppConnectionService.getPresenceGenerator()
+ .sendPresence(account));
if (conversation != null) {
conversation
.setNextEncryption(Message.ENCRYPTION_PGP);
@@ -221,7 +248,7 @@ public abstract class XmppActivity extends Activity {
});
}
-
+
protected void showAddToRosterDialog(final Conversation conversation) {
String jid = conversation.getContactJid();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -241,6 +268,26 @@ public abstract class XmppActivity extends Activity {
});
builder.create().show();
}
+
+ protected void quickEdit(final String previousValue, final OnValueEdited callback) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ View view = (View) getLayoutInflater().inflate(R.layout.quickedit, null);
+ final EditText editor = (EditText) view.findViewById(R.id.editor);
+ editor.setText(previousValue);
+ builder.setView(view);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.edit, new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String value = editor.getText().toString();
+ if (!previousValue.equals(value) && value.trim().length() > 0) {
+ callback.onValueEdited(value);
+ }
+ }
+ });
+ builder.create().show();
+ }
public void selectPresence(final Conversation conversation,
final OnPresenceSelected listener) {
@@ -293,4 +340,18 @@ public abstract class XmppActivity extends Activity {
}
}
}
+
+ protected void onActivityResult(int requestCode, int resultCode,
+ final Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {
+ String contactJid = data.getStringExtra("contact");
+ String conversationUuid = data.getStringExtra("conversation");
+ Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid);
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ xmppConnectionService.inviteToConference(conversation, contactJid);
+ }
+ Log.d("xmppService","inviting "+contactJid+" to "+conversation.getName(true));
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
new file mode 100644
index 00000000..040e6266
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -0,0 +1,69 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+
+public class KnownHostsAdapter extends ArrayAdapter<String> {
+ private ArrayList<String> domains;
+ private Filter domainFilter = new Filter() {
+
+ @Override
+ protected FilterResults performFiltering(CharSequence constraint) {
+ if (constraint != null) {
+ ArrayList<String> suggestions = new ArrayList<String>();
+ final String[] split = constraint.toString().split("@");
+ if (split.length == 1) {
+ for (String domain : domains) {
+ suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
+ }
+ } else if (split.length == 2) {
+ for (String domain : domains) {
+ if (domain.contains(split[1])) {
+ suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
+ }
+ }
+ } else {
+ return new FilterResults();
+ }
+ FilterResults filterResults = new FilterResults();
+ filterResults.values = suggestions;
+ filterResults.count = suggestions.size();
+ return filterResults;
+ } else {
+ return new FilterResults();
+ }
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint,
+ FilterResults results) {
+ ArrayList<String> filteredList = (ArrayList<String>) results.values;
+ if (results != null && results.count > 0) {
+ clear();
+ for (String c : filteredList) {
+ add(c);
+ }
+ notifyDataSetChanged();
+ }
+ }
+ };
+
+ public KnownHostsAdapter(Context context, int viewResourceId,
+ List<String> mKnownHosts) {
+ super(context, viewResourceId, mKnownHosts);
+ domains = new ArrayList<String>(mKnownHosts.size());
+ for (String domain : mKnownHosts) {
+ domains.add(new String(domain));
+ }
+ }
+
+ @Override
+ public Filter getFilter() {
+ return domainFilter;
+ }
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
new file mode 100644
index 00000000..9ef427fc
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java
@@ -0,0 +1,39 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.ListItem;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class ListItemAdapter extends ArrayAdapter<ListItem> {
+
+ public ListItemAdapter(Context context, List<ListItem> objects) {
+ super(context, 0, objects);
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ ListItem item = getItem(position);
+ if (view == null) {
+ view = (View) inflater.inflate(R.layout.contact, null);
+ }
+ TextView name = (TextView) view.findViewById(R.id.contact_display_name);
+ TextView jid = (TextView) view.findViewById(R.id.contact_jid);
+ ImageView picture = (ImageView) view.findViewById(R.id.contact_photo);
+
+ jid.setText(item.getJid());
+ name.setText(item.getDisplayName());
+ picture.setImageBitmap(item.getImage(48, getContext()));
+ return view;
+ }
+
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java
index 529d2b4c..1cd3403c 100644
--- a/src/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/eu/siacs/conversations/utils/UIHelper.java
@@ -17,7 +17,6 @@ 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.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
@@ -45,13 +44,12 @@ import android.text.Html;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.LinearLayout;
import android.widget.QuickContactBadge;
import android.widget.TextView;
public class UIHelper {
private static final int BG_COLOR = 0xFF181818;
- private static final int FG_COLOR = 0xFFE5E5E5;
+ private static final int FG_COLOR = 0xFFFAFAFA;
private static final int TRANSPARENT = 0x00000000;
private static final int DATE_NO_YEAR_FLAGS = DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL;
@@ -69,7 +67,7 @@ public class UIHelper {
} else if (difference < 60 * 15) {
return context.getString(R.string.minutes_ago,
Math.round(difference / 60.0));
- } else if (today(date)) {
+ } else if (today(date) || difference < 6 * 60 * 60) {
java.text.DateFormat df = DateFormat.getTimeFormat(context);
return df.format(date);
} else {
@@ -120,8 +118,9 @@ public class UIHelper {
}
private static int getNameColor(String name) {
- int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
- 0xFFe92727 };
+ /*int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713,
+ 0xFFe92727 };*/
+ int holoColors[] = {0xFFe91e63, 0xFF9c27b0, 0xFF673ab7, 0xFF3f51b5, 0xFF5677fc, 0xFF03a9f4, 0xFF00bcd4, 0xFF009688, 0xFFff5722, 0xFF795548, 0xFF607d8b};
return holoColors[(int) ((name.hashCode() & 0xffffffffl) % holoColors.length)];
}
@@ -165,7 +164,7 @@ public class UIHelper {
if (names.length > 4) {
letters[3] = "\u2026"; // Unicode ellipsis
- colors[3] = 0xFF444444;
+ colors[3] = 0xFF202020;
}
}
@@ -216,7 +215,7 @@ public class UIHelper {
bgColor, fgColor);
}
String[] names = new String[members.size() + 1];
- names[0] = conversation.getMucOptions().getNick();
+ names[0] = conversation.getMucOptions().getActualNick();
for (int i = 0; i < members.size(); ++i) {
names[i + 1] = members.get(i).getName();
}
@@ -343,7 +342,7 @@ public class UIHelper {
if ((currentCon != null)
&& (currentCon.getMode() == Conversation.MODE_MULTI)
&& (!alwaysNotify)) {
- String nick = currentCon.getMucOptions().getNick();
+ String nick = currentCon.getMucOptions().getActualNick();
Pattern highlight = generateNickHighlightPattern(nick);
Matcher m = highlight.matcher(currentCon.getLatestMessage()
.getBody());
@@ -463,7 +462,7 @@ public class UIHelper {
private static boolean wasHighlighted(Conversation conversation) {
List<Message> messages = conversation.getMessages();
- String nick = conversation.getMucOptions().getNick();
+ String nick = conversation.getMucOptions().getActualNick();
Pattern highlight = generateNickHighlightPattern(nick);
for (int i = messages.size() - 1; i >= 0; --i) {
if (messages.get(i).isRead()) {
@@ -491,7 +490,7 @@ public class UIHelper {
public static AlertDialog getVerifyFingerprintDialog(
final ConversationActivity activity,
- final Conversation conversation, final LinearLayout msg) {
+ final Conversation conversation, final View msg) {
final Contact contact = conversation.getContact();
final Account account = conversation.getAccount();
diff --git a/src/eu/siacs/conversations/xml/XmlReader.java b/src/eu/siacs/conversations/xml/XmlReader.java
index 98bee3ee..10b2fb06 100644
--- a/src/eu/siacs/conversations/xml/XmlReader.java
+++ b/src/eu/siacs/conversations/xml/XmlReader.java
@@ -81,6 +81,8 @@ public class XmlReader {
throw new IOException("xml parser mishandled ArrayIndexOufOfBounds", e);
} catch (StringIndexOutOfBoundsException e) {
throw new IOException("xml parser mishandled StringIndexOufOfBounds", e);
+ } catch (NullPointerException e) {
+ throw new IOException("null pointer in xml parser");
}
return null;
}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index b2829c6e..72018394 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -18,7 +18,6 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
-import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
@@ -793,20 +792,10 @@ public class XmppConnection implements Runnable {
this.sendPacket(packet, null);
}
- public void sendMessagePacket(MessagePacket packet,
- OnMessagePacketReceived callback) {
- this.sendPacket(packet, callback);
- }
-
public void sendPresencePacket(PresencePacket packet) {
this.sendPacket(packet, null);
}
-
- public void sendPresencePacket(PresencePacket packet,
- OnPresencePacketReceived callback) {
- this.sendPacket(packet, callback);
- }
-
+
private synchronized void sendPacket(final AbstractStanza packet,
PacketReceived callback) {
// TODO dont increment stanza count if packet = request packet or ack;
@@ -926,14 +915,10 @@ public class XmppConnection implements Runnable {
public List<String> findDiscoItemsByFeature(String feature) {
List<String> items = new ArrayList<String>();
- Iterator<Entry<String, List<String>>> it = this.disco.entrySet()
- .iterator();
- while (it.hasNext()) {
- Entry<String, List<String>> pairs = it.next();
- if (pairs.getValue().contains(feature)) {
- items.add(pairs.getKey());
+ for (Entry<String, List<String>> cursor : disco.entrySet()) {
+ if (cursor.getValue().contains(feature)) {
+ items.add(cursor.getKey());
}
- it.remove();
}
return items;
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 508fe95c..f1a0373c 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -83,7 +83,7 @@ public class JingleConnection {
sendSuccess();
if (acceptedAutomatically) {
message.markUnread();
- JingleConnection.this.mXmppConnectionService.updateUi(message.getConversation(), true);
+ JingleConnection.this.mXmppConnectionService.notifyUi(message.getConversation(), true);
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
@@ -99,6 +99,7 @@ public class JingleConnection {
@Override
public void onFileTransferAborted() {
+ JingleConnection.this.sendCancel();
JingleConnection.this.cancel();
}
};
@@ -276,20 +277,30 @@ public class JingleConnection {
} else {
message.markUnread();
Log.d("xmppService","not auto accepting new file offer with size: "+size+" allowed size:"+this.mJingleConnectionManager.getAutoAcceptFileSize());
- this.mXmppConnectionService.updateUi(conversation, true);
+ this.mXmppConnectionService.notifyUi(conversation, true);
}
this.file = this.mXmppConnectionService.getFileBackend().getJingleFile(message,false);
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
- this.file.setKey(conversation.getSymmetricKey());
+ byte[] key = conversation.getSymmetricKey();
+ if (key==null) {
+ this.sendCancel();
+ this.cancel();
+ return;
+ } else {
+ this.file.setKey(conversation.getSymmetricKey());
+ }
}
this.file.setExpectedSize(size);
} else {
+ this.sendCancel();
this.cancel();
}
} else {
+ this.sendCancel();
this.cancel();
}
} else {
+ this.sendCancel();
this.cancel();
}
}
@@ -410,6 +421,7 @@ public class JingleConnection {
connection.setActivated(true);
} else {
Log.d("xmppService","activated connection not found");
+ this.sendCancel();
this.cancel();
}
}
@@ -495,10 +507,8 @@ public class JingleConnection {
private JingleSocks5Transport chooseConnection() {
JingleSocks5Transport connection = null;
- Iterator<Entry<String, JingleSocks5Transport>> it = this.connections.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, JingleSocks5Transport> pairs = it.next();
- JingleSocks5Transport currentConnection = pairs.getValue();
+ for (Entry<String, JingleSocks5Transport> cursor : connections.entrySet()) {
+ JingleSocks5Transport currentConnection = cursor.getValue();
//Log.d("xmppService","comparing candidate: "+currentConnection.getCandidate().toString());
if (currentConnection.isEstablished()&&(currentConnection.getCandidate().isUsedByCounterpart()||(!currentConnection.getCandidate().isOurs()))) {
//Log.d("xmppService","is usable");
@@ -521,7 +531,6 @@ public class JingleConnection {
}
}
}
- it.remove();
}
return connection;
}
@@ -603,8 +612,7 @@ public class JingleConnection {
this.mJingleConnectionManager.finishConnection(this);
}
- void cancel() {
- this.sendCancel();
+ public void cancel() {
this.disconnect();
if (this.message!=null) {
if (this.responder.equals(account.getFullJid())) {
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index d4af624a..f01d7fa9 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -2,12 +2,11 @@ package eu.siacs.conversations.xmpp.jingle;
import java.math.BigInteger;
import java.security.SecureRandom;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-
+import java.util.concurrent.CopyOnWriteArrayList;
+import android.annotation.SuppressLint;
import android.util.Log;
-
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
@@ -20,10 +19,11 @@ public class JingleConnectionManager {
private XmppConnectionService xmppConnectionService;
- private List<JingleConnection> connections = new ArrayList<JingleConnection>();
+ private List<JingleConnection> connections = new CopyOnWriteArrayList<JingleConnection>();
private HashMap<String, JingleCandidate> primaryCandidates = new HashMap<String, JingleCandidate>();
+ @SuppressLint("TrulyRandom")
private SecureRandom random = new SecureRandom();
public JingleConnectionManager(XmppConnectionService service) {
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
index 228827ab..d2c84325 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
@@ -137,6 +137,7 @@ public class JingleSocks5Transport extends JingleTransport {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
inputStream.skip(45);
+ socket.setSoTimeout(30000);
file.getParentFile().mkdirs();
file.createNewFile();
OutputStream fileOutputStream = getOutputStream(file);