aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eu/siacs/conversations/entities/AbstractEntity.java5
-rw-r--r--src/eu/siacs/conversations/entities/Account.java7
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java6
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java19
-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/generator/AbstractGenerator.java49
-rw-r--r--src/eu/siacs/conversations/generator/IqGenerator.java31
-rw-r--r--src/eu/siacs/conversations/generator/MessageGenerator.java33
-rw-r--r--src/eu/siacs/conversations/generator/PresenceGenerator.java10
-rw-r--r--src/eu/siacs/conversations/parser/AbstractParser.java15
-rw-r--r--src/eu/siacs/conversations/parser/IqParser.java20
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java55
-rw-r--r--src/eu/siacs/conversations/parser/PresenceParser.java14
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java294
-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.java244
-rw-r--r--src/eu/siacs/conversations/ui/ConversationActivity.java29
-rw-r--r--src/eu/siacs/conversations/ui/ConversationFragment.java562
-rw-r--r--src/eu/siacs/conversations/ui/EditAccountDialog.java (renamed from src/eu/siacs/conversations/ui/EditAccount.java)4
-rw-r--r--src/eu/siacs/conversations/ui/ManageAccountActivity.java73
-rw-r--r--src/eu/siacs/conversations/ui/MucDetailsActivity.java214
-rw-r--r--src/eu/siacs/conversations/ui/OnPresenceSelected.java5
-rw-r--r--src/eu/siacs/conversations/ui/StartConversationActivity.java (renamed from src/eu/siacs/conversations/ui/StartConversation.java)180
-rw-r--r--src/eu/siacs/conversations/ui/XmppActivity.java69
-rw-r--r--src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java (renamed from src/eu/siacs/conversations/utils/KnownHostsAdapter.java)4
-rw-r--r--src/eu/siacs/conversations/ui/adapter/ListItemAdapter.java39
-rw-r--r--src/eu/siacs/conversations/ui/adapter/MessageAdapter.java478
-rw-r--r--src/eu/siacs/conversations/utils/UIHelper.java7
-rw-r--r--src/eu/siacs/conversations/utils/Validator.java2
-rw-r--r--src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java7
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java85
33 files changed, 1746 insertions, 1282 deletions
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 ac62cf7b..b19889bf 100644
--- a/src/eu/siacs/conversations/entities/Account.java
+++ b/src/eu/siacs/conversations/entities/Account.java
@@ -4,6 +4,7 @@ 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;
@@ -18,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";
@@ -41,7 +40,6 @@ public class Account extends AbstractEntity{
public static final int STATUS_ONLINE = 1;
public static final int STATUS_NO_INTERNET = 2;
public static final int STATUS_UNAUTHORIZED = 3;
- public static final int STATUS_TLS_ERROR = 4;
public static final int STATUS_SERVER_NOT_FOUND = 5;
public static final int STATUS_SERVER_REQUIRES_TLS = 6;
@@ -72,6 +70,9 @@ public class Account extends AbstractEntity{
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";
}
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
index c4e151cb..38c03410 100644
--- a/src/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -122,4 +122,10 @@ public class Bookmark implements ListItem {
}
return element;
}
+
+ public void unregisterConversation() {
+ if (this.mJoinedConversation != null) {
+ this.mJoinedConversation.deregisterWithBookmark();
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index 70752adc..76fe84cf 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -16,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;
@@ -117,7 +114,7 @@ public class Conversation extends AbstractEntity {
this.messages.get(i).markRead();
}
}
-
+
public String popLatestMarkableMessageId() {
String id = this.latestMarkableMessageId;
this.latestMarkableMessageId = null;
@@ -144,7 +141,8 @@ 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) {
+ } else if (getMode() == MODE_MULTI && bookmark != null
+ && bookmark.getName() != null) {
return bookmark.getName();
} else {
return this.getContact().getDisplayName();
@@ -241,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) {
@@ -270,7 +268,7 @@ public class Conversation extends AbstractEntity {
}
}
}
-
+
public void endOtrIfNeeded() {
if (this.otrSession != null) {
if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) {
@@ -293,6 +291,9 @@ public class Conversation extends AbstractEntity {
public String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
+ if (getOtrSession()== null) {
+ return "";
+ }
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
.getRemotePublicKey();
StringBuilder builder = new StringBuilder(
@@ -375,7 +376,7 @@ public class Conversation extends AbstractEntity {
public void setSymmetricKey(byte[] key) {
this.symmetricKey = key;
}
-
+
public byte[] getSymmetricKey() {
return this.symmetricKey;
}
@@ -384,7 +385,7 @@ public class Conversation extends AbstractEntity {
this.bookmark = bookmark;
this.bookmark.setConversation(this);
}
-
+
public void deregisterWithBookmark() {
if (this.bookmark != null) {
this.bookmark.setConversation(null);
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/generator/AbstractGenerator.java b/src/eu/siacs/conversations/generator/AbstractGenerator.java
new file mode 100644
index 00000000..49b5d614
--- /dev/null
+++ b/src/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -0,0 +1,49 @@
+package eu.siacs.conversations.generator;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import android.util.Base64;
+
+public abstract class AbstractGenerator {
+ public final String[] FEATURES = { "urn:xmpp:jingle:1",
+ "urn:xmpp:jingle:apps:file-transfer:3",
+ "urn:xmpp:jingle:transports:s5b:1",
+ "urn:xmpp:jingle:transports:ibb:1",
+ "urn:xmpp:receipts",
+ "urn:xmpp:chat-markers:0",
+ "http://jabber.org/protocol/muc",
+ "jabber:x:conference",
+ "http://jabber.org/protocol/caps",
+ "http://jabber.org/protocol/disco#info"};
+ //public final String[] FEATURES = { "http://jabber.org/protocol/muc","http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/caps" };
+
+ //public final String IDENTITY_NAME = "Exodus 0.9.1";
+ //public final String IDENTITY_TYPE = "pc";
+
+
+ public final String IDENTITY_NAME = "Conversations 0.5";
+ public final String IDENTITY_TYPE = "phone";
+
+ public String getCapHash() {
+ StringBuilder s = new StringBuilder();
+ s.append("client/"+IDENTITY_TYPE+"//"+IDENTITY_NAME+"<");
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ }
+ catch(NoSuchAlgorithmException e) {
+ return null;
+ }
+ List<String> features = Arrays.asList(FEATURES);
+ Collections.sort(features);
+ for(String feature : features) {
+ s.append(feature+"<");
+ }
+ byte[] sha1 = md.digest(s.toString().getBytes());
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
+ }
+}
diff --git a/src/eu/siacs/conversations/generator/IqGenerator.java b/src/eu/siacs/conversations/generator/IqGenerator.java
new file mode 100644
index 00000000..7b3350d4
--- /dev/null
+++ b/src/eu/siacs/conversations/generator/IqGenerator.java
@@ -0,0 +1,31 @@
+package eu.siacs.conversations.generator;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
+public class IqGenerator extends AbstractGenerator {
+
+
+
+ public IqPacket discoResponse(IqPacket request) {
+ IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT);
+ packet.setId(request.getId());
+ packet.setTo(request.getFrom());
+ Element query = packet.addChild("query","http://jabber.org/protocol/disco#info");
+ query.setAttribute("node", request.query().getAttribute("node"));
+ Element identity = query.addChild("identity");
+ identity.setAttribute("category","client");
+ identity.setAttribute("type", this.IDENTITY_TYPE);
+ identity.setAttribute("name", IDENTITY_NAME);
+ List<String> features = Arrays.asList(FEATURES);
+ Collections.sort(features);
+ for(String feature : features) {
+ query.addChild("feature").setAttribute("var",feature);
+ }
+ return packet;
+ }
+}
diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java
index 5a216a7e..4449a7ec 100644
--- a/src/eu/siacs/conversations/generator/MessageGenerator.java
+++ b/src/eu/siacs/conversations/generator/MessageGenerator.java
@@ -128,4 +128,37 @@ public class MessageGenerator {
packet.setFrom(conversation.getAccount().getJid());
return packet;
}
+
+ public MessagePacket directInvite(Conversation conversation, String contact) {
+ MessagePacket packet = new MessagePacket();
+ packet.setType(MessagePacket.TYPE_NORMAL);
+ packet.setTo(contact);
+ packet.setFrom(conversation.getAccount().getFullJid());
+ Element x = packet.addChild("x", "jabber:x:conference");
+ x.setAttribute("jid", conversation.getContactJid().split("/")[0]);
+ return packet;
+ }
+
+ public MessagePacket invite(Conversation conversation, String contact) {
+ 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);
+ x.addChild(invite);
+ packet.addChild(x);
+ return packet;
+ }
+
+ public MessagePacket received(Account account, MessagePacket originalMessage, String namespace) {
+ MessagePacket receivedPacket = new MessagePacket();
+ receivedPacket.setType(MessagePacket.TYPE_NORMAL);
+ receivedPacket.setTo(originalMessage.getFrom());
+ receivedPacket.setFrom(account.getFullJid());
+ Element received = receivedPacket.addChild("received",namespace);
+ received.setAttribute("id", originalMessage.getId());
+ return receivedPacket;
+ }
}
diff --git a/src/eu/siacs/conversations/generator/PresenceGenerator.java b/src/eu/siacs/conversations/generator/PresenceGenerator.java
index a301392e..b3431568 100644
--- a/src/eu/siacs/conversations/generator/PresenceGenerator.java
+++ b/src/eu/siacs/conversations/generator/PresenceGenerator.java
@@ -2,9 +2,10 @@ package eu.siacs.conversations.generator;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
-public class PresenceGenerator {
+public class PresenceGenerator extends AbstractGenerator {
private PresencePacket subscription(String type, Contact contact) {
PresencePacket packet = new PresencePacket();
@@ -38,6 +39,13 @@ public class PresenceGenerator {
packet.addChild("status").setContent("online");
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
+ String capHash = getCapHash();
+ if (capHash != null) {
+ Element cap = packet.addChild("c","http://jabber.org/protocol/caps");
+ cap.setAttribute("hash", "sha-1");
+ cap.setAttribute("node","http://conversions.siacs.eu");
+ cap.setAttribute("ver", capHash);
+ }
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
index acbeee4d..023fb4df 100644
--- a/src/eu/siacs/conversations/parser/IqParser.java
+++ b/src/eu/siacs/conversations/parser/IqParser.java
@@ -38,6 +38,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
}
}
}
+ mXmppConnectionService.updateRosterUi();
}
@Override
@@ -55,23 +56,8 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
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);
+ IqPacket response = mXmppConnectionService.getIqGenerator().discoResponse(packet);
+ account.getXmppConnection().sendIqPacket(response, null);
} else {
if ((packet.getType() == IqPacket.TYPE_GET)
|| (packet.getType() == IqPacket.TYPE_SET)) {
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index 1673fbf0..a4fcc810 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -80,6 +80,7 @@ public class MessageParser extends AbstractParser implements
mXmppConnectionService.onOtrSessionEstablished(conversation);
} else if ((before != after) && (after == SessionStatus.FINISHED)) {
conversation.resetOtrSession();
+ mXmppConnectionService.updateConversationUi();
}
if ((body == null) || (body.isEmpty())) {
return null;
@@ -109,6 +110,9 @@ public class MessageParser extends AbstractParser implements
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")) {
@@ -121,7 +125,7 @@ public class MessageParser extends AbstractParser implements
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;
@@ -174,6 +178,9 @@ public class MessageParser extends AbstractParser implements
} else {
fullJid = message.getAttribute("to");
}
+ if (fullJid==null) {
+ return null;
+ }
String[] parts = fullJid.split("/");
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, parts[0], false);
@@ -214,15 +221,29 @@ public class MessageParser extends AbstractParser implements
updateLastseen(packet, account, false);
mXmppConnectionService.markMessage(account, fromParts[0], id,
Message.STATUS_SEND_RECEIVED);
- } else if (packet.hasChild("x")) {
- Element x = packet.findChild("x");
+ } else if (packet.hasChild("x","http://jabber.org/protocol/muc#user")) {
+ Element x = packet.findChild("x","http://jabber.org/protocol/muc#user");
if (x.hasChild("invite")) {
- mXmppConnectionService
+ Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account,
packet.getAttribute("from"), true);
- mXmppConnectionService.updateConversationUi();
+ if (!conversation.getMucOptions().online()) {
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
}
+ } else if (packet.hasChild("x", "jabber:x:conference")) {
+ Element x = packet.findChild("x", "jabber:x:conference");
+ String jid = x.getAttribute("jid");
+ if (jid!=null) {
+ Conversation conversation = mXmppConnectionService
+ .findOrCreateConversation(account,jid, true);
+ if (!conversation.getMucOptions().online()) {
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
+ }
}
}
@@ -274,6 +295,8 @@ public class MessageParser extends AbstractParser implements
message.markUnread();
}
}
+ } else {
+ parseNormal(packet, account);
}
} else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
@@ -283,6 +306,8 @@ public class MessageParser extends AbstractParser implements
message.markUnread();
} else {
message.getConversation().markRead();
+ lastCarbonMessageReceived = SystemClock
+ .elapsedRealtime();
notify = false;
}
}
@@ -291,26 +316,20 @@ public class MessageParser extends AbstractParser implements
return;
} else if (packet.getType() == MessagePacket.TYPE_NORMAL) {
this.parseNormal(packet, account);
+ return;
}
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);
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, packet, "urn:xmpp:chat-markers:0");
+ mXmppConnectionService.sendMessagePacket(account, receipt);
+ }
+ if (packet.hasChild("request", "urn:xmpp:receipts")) {
+ MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, packet, "urn:xmpp:receipts");
+ mXmppConnectionService.sendMessagePacket(account, receipt);
}
}
Conversation conversation = message.getConversation();
diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java
index bd2aa636..33f4185f 100644
--- a/src/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/eu/siacs/conversations/parser/PresenceParser.java
@@ -21,22 +21,19 @@ public class PresenceParser extends AbstractParser implements
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.updateConversationUi();
- }
}
}
+ mXmppConnectionService.updateConversationUi();
}
public void parseContactPresence(PresencePacket packet, Account account) {
@@ -99,6 +96,7 @@ public class PresenceParser extends AbstractParser implements
}
}
}
+ mXmppConnectionService.updateRosterUi();
}
@Override
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index c43a34b7..de0658d4 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -15,6 +15,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
+import de.duenndns.ssl.MemorizingTrustManager;
+
import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
@@ -27,6 +29,7 @@ import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
import eu.siacs.conversations.entities.Presences;
+import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.generator.PresenceGenerator;
import eu.siacs.conversations.parser.IqParser;
@@ -46,7 +49,6 @@ import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnStatusChanged;
-import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.JingleConnectionManager;
import eu.siacs.conversations.xmpp.jingle.OnJinglePacketReceived;
@@ -90,6 +92,8 @@ public class XmppConnectionService extends Service {
public static final long CARBON_GRACE_PERIOD = 60000L;
private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts";
+
+ private MemorizingTrustManager mMemorizingTrustManager;
private MessageParser mMessageParser = new MessageParser(this);
private PresenceParser mPresenceParser = new PresenceParser(this);
@@ -105,12 +109,12 @@ public class XmppConnectionService extends Service {
private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
private OnAccountUpdate mOnAccountUpdate = null;
- private OnTLSExceptionReceived tlsException = null;
+ private OnRosterUpdate mOnRosterUpdate = 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)) {
@@ -120,11 +124,6 @@ public class XmppConnectionService extends Service {
}
};
- public void setOnTLSExceptionReceivedListener(
- OnTLSExceptionReceived listener) {
- tlsException = listener;
- }
-
private SecureRandom mRandom;
private ContentObserver contactObserver = new ContentObserver(null) {
@@ -147,6 +146,12 @@ public class XmppConnectionService extends Service {
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) {
@@ -195,6 +200,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()) {
@@ -246,18 +266,12 @@ public class XmppConnectionService extends Service {
return message;
}
- public Conversation findMuc(Bookmark bookmark) {
- return findMuc(bookmark.getJid(), bookmark.getAccount());
+ public Conversation find(Bookmark bookmark) {
+ return find(bookmark.getAccount(),bookmark.getJid());
}
- public Conversation findMuc(String jid, Account account) {
- for (Conversation conversation : this.conversations) {
- if (conversation.getContactJid().split("/")[0].equals(jid)
- && (conversation.getAccount() == account)) {
- return conversation;
- }
- }
- return null;
+ public Conversation find(Account account, String jid) {
+ return find(getConversations(),account,jid);
}
public class XmppConnectionBinder extends Binder {
@@ -352,6 +366,7 @@ public class XmppConnectionService extends Service {
ExceptionHelper.init(getApplicationContext());
PRNGFixes.apply();
this.mRandom = new SecureRandom();
+ this.mMemorizingTrustManager = new MemorizingTrustManager(getApplicationContext());
this.databaseBackend = DatabaseBackend
.getInstance(getApplicationContext());
this.fileBackend = new FileBackend(getApplicationContext());
@@ -451,32 +466,7 @@ public class XmppConnectionService extends Service {
connection
.setOnUnregisteredIqPacketReceivedListener(this.mIqParser);
connection.setOnJinglePacketReceivedListener(this.jingleListener);
- connection
- .setOnTLSExceptionReceivedListener(new OnTLSExceptionReceived() {
-
- @Override
- public void onTLSExceptionReceived(String fingerprint,
- Account account) {
- Log.d(LOGTAG, "tls exception arrived in service");
- if (tlsException != null) {
- tlsException.onTLSExceptionReceived(fingerprint,
- account);
- }
- }
- });
- connection.setOnBindListener(new OnBindListener() {
-
- @Override
- public void onBind(final Account account) {
- account.getRoster().clearPresences();
- account.clearPresences(); // self presences
- fetchRosterFromServer(account);
- fetchBookmarks(account);
- sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
- connectMultiModeConversations(account);
- updateConversationUi();
- }
- });
+ connection.setOnBindListener(this.mOnBindListener);
return connection;
}
@@ -528,11 +518,13 @@ public class XmppConnectionService extends Service {
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
message.getConversation().endOtrIfNeeded();
+ failWaitingOtrMessages(message.getConversation());
packet = mMessageGenerator.generatePgpChat(message);
message.setStatus(Message.STATUS_SEND);
send = true;
} else {
message.getConversation().endOtrIfNeeded();
+ failWaitingOtrMessages(message.getConversation());
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
message.setStatus(Message.STATUS_SEND);
}
@@ -681,16 +673,16 @@ public class XmppConnectionService extends Service {
if (storage!=null) {
for(Element item : storage.getChildren()) {
if (item.getName().equals("conference")) {
- Log.d(LOGTAG,item.toString());
Bookmark bookmark = Bookmark.parse(item,account);
bookmarks.add(bookmark);
- Conversation conversation = findMuc(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);
}
}
}
@@ -792,8 +784,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;
}
@@ -801,16 +793,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);
@@ -840,10 +840,6 @@ 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);
- }
updateConversationUi();
return conversation;
}
@@ -891,6 +887,16 @@ public class XmppConnectionService extends Service {
}
public void deleteAccount(Account account) {
+ for(Conversation conversation : conversations) {
+ if (conversation.getAccount() == account) {
+ if (conversation.getMode() == Conversation.MODE_MULTI) {
+ leaveMuc(conversation);
+ } else if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ conversation.endOtrIfNeeded();
+ }
+ conversations.remove(conversation);
+ }
+ }
if (account.getXmppConnection() != null) {
this.disconnect(account, true);
}
@@ -920,6 +926,14 @@ public class XmppConnectionService extends Service {
public void removeOnAccountListChangedListener() {
this.mOnAccountUpdate = null;
}
+
+ public void setOnRosterUpdateListener(OnRosterUpdate listener) {
+ this.mOnRosterUpdate = listener;
+ }
+
+ public void removeOnRosterUpdateListener() {
+ this.mOnRosterUpdate = null;
+ }
public void connectMultiModeConversations(Account account) {
List<Conversation> conversations = getConversations();
@@ -934,39 +948,44 @@ 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();
+ String joinJid = conversation.getMucOptions().getJoinJid();
+ 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);
+ if (!joinJid.equals(conversation.getContactJid())) {
+ conversation.setContactJid(joinJid);
+ databaseBackend.updateConversation(conversation);
+ }
} 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);
+ account.pendingConferenceJoins.add(conversation);
}
- 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);
}
private OnRenameListener renameListener = null;
+ private IqGenerator mIqGenerator = new IqGenerator();
public void setOnRenameListener(OnRenameListener listener) {
this.renameListener = listener;
@@ -974,6 +993,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() {
@@ -984,17 +1004,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();
@@ -1004,26 +1026,35 @@ public class XmppConnectionService extends Service {
}
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");
- sendPresencePacket(conversation.getAccount(),packet);
- conversation.getMucOptions().setOffline();
- conversation.deregisterWithBookmark();
- Log.d(LOGTAG,conversation.getAccount().getJid()+" leaving muc "+conversation.getContactJid());
+ 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) {
@@ -1170,10 +1201,6 @@ public class XmppConnectionService extends Service {
this.databaseBackend.updateConversation(conversation);
}
- public void removeOnTLSExceptionReceivedListener() {
- this.tlsException = null;
- }
-
public void reconnectAccount(final Account account, final boolean force) {
new Thread(new Runnable() {
@@ -1194,22 +1221,9 @@ public class XmppConnectionService extends Service {
}).start();
}
- 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());
- sendMessagePacket(conversation.getAccount(),packet);
- }
-
+ public void invite(Conversation conversation, String contact) {
+ MessagePacket packet = mMessageGenerator.invite(conversation, contact);
+ sendMessagePacket(conversation.getAccount(),packet);
}
public boolean markMessage(Account account, String recipient, String uuid,
@@ -1269,6 +1283,12 @@ public class XmppConnectionService extends Service {
mOnAccountUpdate.onAccountUpdate();
}
}
+
+ public void updateRosterUi() {
+ if (mOnRosterUpdate != null) {
+ mOnRosterUpdate.onRosterUpdate();
+ }
+ }
public Account findAccountByJid(String accountJid) {
for (Account account : this.accounts) {
@@ -1278,6 +1298,15 @@ public class XmppConnectionService extends Service {
}
return null;
}
+
+ public Conversation findConversationByUuid(String uuid) {
+ for (Conversation conversation : getConversations()) {
+ if (conversation.getUuid().equals(uuid)) {
+ return conversation;
+ }
+ }
+ return null;
+ }
public void markRead(Conversation conversation) {
conversation.markRead();
@@ -1288,10 +1317,23 @@ public class XmppConnectionService extends Service {
this.sendMessagePacket(conversation.getAccount(), mMessageGenerator.confirm(account, to, id));
}
}
+
+ public void failWaitingOtrMessages(Conversation conversation) {
+ for (Message message : conversation.getMessages()) {
+ if (message.getEncryption() == Message.ENCRYPTION_OTR
+ && message.getStatus() == Message.STATUS_WAITING) {
+ markMessage(message, Message.STATUS_SEND_FAILED);
+ }
+ }
+ }
public SecureRandom getRNG() {
return this.mRandom;
}
+
+ public MemorizingTrustManager getMemorizingTrustManager() {
+ return this.mMemorizingTrustManager;
+ }
public PowerManager getPowerManager() {
return this.pm;
@@ -1367,6 +1409,10 @@ public class XmppConnectionService extends Service {
return this.mPresenceGenerator;
}
+ public IqGenerator getIqGenerator() {
+ return this.mIqGenerator ;
+ }
+
public JingleConnectionManager getJingleConnectionManager() {
return this.mJingleConnectionManager;
}
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 9321f229..7c13c518 100644
--- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -21,19 +21,19 @@ 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;
+import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
+import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public class ContactDetailsActivity extends XmppActivity {
public static final String ACTION_VIEW_CONTACT = "view_contact";
@@ -41,11 +41,10 @@ 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;
@@ -63,16 +62,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
@@ -92,7 +81,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();
@@ -101,6 +91,74 @@ 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));
+ }
+ }
+ };
+
+ private OnAccountUpdate accountUpdate = new OnAccountUpdate() {
+
+ @Override
+ public void onAccountUpdate() {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ populateView();
+ }
+ });
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -136,20 +194,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("#");
@@ -171,21 +230,26 @@ public class ContactDetailsActivity extends XmppActivity {
}
private void populateView() {
+ send.setOnCheckedChangeListener(null);
+ receive.setOnCheckedChangeListener(null);
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)){
+ } 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);
@@ -195,8 +259,19 @@ public class ContactDetailsActivity extends XmppActivity {
receive.setChecked(false);
}
}
+ if (contact.getAccount().getStatus() == Account.STATUS_ONLINE) {
+ receive.setEnabled(true);
+ send.setEnabled(true);
+ } else {
+ receive.setEnabled(false);
+ send.setEnabled(false);
+ }
+
+ send.setOnCheckedChangeListener(this.mOnSendCheckedChange);
+ receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange);
- lastseen.setText(UIHelper.lastseen(getApplicationContext(),contact.lastseen.time));
+ lastseen.setText(UIHelper.lastseen(getApplicationContext(),
+ contact.lastseen.time));
switch (contact.getMostAvailableStatus()) {
case Presences.CHAT:
@@ -229,13 +304,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);
@@ -260,17 +337,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) {
-
+
}
}
}
@@ -282,9 +362,12 @@ 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);
+ xmppConnectionService.setOnAccountListChangedListener(this.accountUpdate );
+ if ((accountJid != null) && (contactJid != null)) {
+ Account account = xmppConnectionService
+ .findAccountByJid(accountJid);
+ if (account == null) {
return;
}
this.contact = account.getRoster().getContact(contactJid);
@@ -295,79 +378,8 @@ public class ContactDetailsActivity extends XmppActivity {
@Override
protected void onStop() {
super.onStop();
- XmppConnectionService xcs = activity.xmppConnectionService;
- PresencePacket packet = null;
- 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);
- packet = xcs.getPresenceGenerator().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) {
- if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
- packet = xcs.getPresenceGenerator().sendPresenceUpdatesTo(contact);
- } else {
- contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
- }
- }
- updated = true;
- }
- }
- }
- if (contact.getOption(Contact.Options.TO)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.TO);
- packet = xcs.getPresenceGenerator().stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (contact.getOption(Contact.Options.ASKING)) {
- if (!receive.isChecked()) {
- if (online) {
- contact.resetOption(Contact.Options.ASKING);
- packet = xcs.getPresenceGenerator().stopPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- } else {
- if (receive.isChecked()) {
- if (online) {
- contact.setOption(Contact.Options.ASKING);
- packet = xcs.getPresenceGenerator().requestPresenceUpdatesFrom(contact);
- }
- updated = true;
- }
- }
- }
- if (updated) {
- if (online) {
- if (packet!=null) {
- xcs.sendPresencePacket(contact.getAccount(), packet);
- }
- 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();
+ xmppConnectionService.removeOnAccountListChangedListener();
}
}
diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java
index 66db353b..aa4fda4e 100644
--- a/src/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/eu/siacs/conversations/ui/ConversationActivity.java
@@ -98,7 +98,7 @@ public class ConversationActivity extends XmppActivity {
swapConversationFragment();
} else {
startActivity(new Intent(getApplicationContext(),
- StartConversation.class));
+ StartConversationActivity.class));
finish();
}
}
@@ -306,23 +306,22 @@ 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 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());
if (this.getSelectedConversation() != null) {
if (this.getSelectedConversation().getLatestMessage()
.getEncryption() != Message.ENCRYPTION_NONE) {
@@ -333,7 +332,7 @@ public class ConversationActivity extends XmppActivity {
menuAttach.setVisible(false);
} else {
menuMucDetails.setVisible(false);
- menuInviteContacts.setVisible(false);
+ menuInviteContact.setVisible(false);
}
}
}
@@ -458,7 +457,7 @@ public class ConversationActivity extends XmppActivity {
attachFilePopup.show();
break;
case R.id.action_add:
- startActivity(new Intent(this, StartConversation.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
break;
case R.id.action_archive:
this.endConversation(getSelectedConversation());
@@ -472,17 +471,13 @@ public class ConversationActivity extends XmppActivity {
}
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();
@@ -569,7 +564,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();
@@ -699,7 +694,7 @@ public class ConversationActivity extends XmppActivity {
finish();
} else if (conversationList.size() <= 0) {
// add no history
- startActivity(new Intent(this, StartConversation.class));
+ startActivity(new Intent(this, StartConversationActivity.class));
finish();
} else {
spl.openPane();
diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java
index 01bab773..1df59843 100644
--- a/src/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/eu/siacs/conversations/ui/ConversationFragment.java
@@ -1,53 +1,45 @@
package eu.siacs.conversations.ui;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
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.ui.adapter.MessageAdapter;
+import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jingle.JingleConnection;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.IntentSender.SendIntentException;
-import android.graphics.Bitmap;
-import android.graphics.Typeface;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.Selection;
-import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AbsListView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
+
import android.widget.EditText;
-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;
@@ -58,12 +50,8 @@ public class ConversationFragment extends Fragment {
protected ListView messagesView;
protected LayoutInflater inflater;
protected List<Message> messageList = new ArrayList<Message>();
- protected ArrayAdapter<Message> messageListAdapter;
+ protected MessageAdapter messageListAdapter;
protected Contact contact;
- protected BitmapCache mBitmapCache = new BitmapCache();
-
- protected int mPrimaryTextColor;
- protected int mSecondaryTextColor;
protected String queuedPqpMessage = null;
@@ -73,8 +61,6 @@ public class ConversationFragment extends Fragment {
private TextView snackbarMessage;
private TextView snackbarAction;
- protected Bitmap selfBitmap;
-
private boolean useSubject = true;
private boolean messagesLoaded = false;
@@ -113,18 +99,27 @@ public class ConversationFragment extends Fragment {
}
}
};
-
+
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
@@ -172,17 +167,18 @@ public class ConversationFragment extends Fragment {
@Override
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
-
- final DisplayMetrics metrics = getResources().getDisplayMetrics();
-
- 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);
@@ -195,376 +191,16 @@ public class ConversationFragment extends Fragment {
messagesView = (ListView) view.findViewById(R.id.messages_view);
messagesView.setOnScrollListener(mOnScrollListener);
messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
-
- messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
- .getApplicationContext(), R.layout.message_sent,
- this.messageList) {
-
- private static final int SENT = 0;
- private static final int RECIEVED = 1;
- private static final int STATUS = 2;
-
- @Override
- public int getViewTypeCount() {
- return 3;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (getItem(position).getType() == Message.TYPE_STATUS) {
- return STATUS;
- } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
- return RECIEVED;
- } else {
- return SENT;
- }
- }
-
- private void displayStatus(ViewHolder viewHolder, Message message) {
- String filesize = null;
- String info = null;
- boolean error = false;
- boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
- && message.getStatus() <= Message.STATUS_RECIEVED;
- if (message.getType() == Message.TYPE_IMAGE) {
- String[] fileParams = message.getBody().split(",");
- try {
- long size = Long.parseLong(fileParams[0]);
- filesize = size / 1024 + " KB";
- } catch (NumberFormatException e) {
- filesize = "0 KB";
- }
- }
- switch (message.getStatus()) {
- case Message.STATUS_WAITING:
- info = getString(R.string.waiting);
- break;
- case Message.STATUS_UNSEND:
- info = getString(R.string.sending);
- break;
- case Message.STATUS_OFFERED:
- info = getString(R.string.offering);
- break;
- case Message.STATUS_SEND_FAILED:
- info = getString(R.string.send_failed);
- error = true;
- break;
- case Message.STATUS_SEND_REJECTED:
- info = getString(R.string.send_rejected);
- error = true;
- break;
- case Message.STATUS_RECEPTION_FAILED:
- info = getString(R.string.reception_failed);
- error = true;
- default:
- if (multiReceived) {
- info = message.getCounterpart();
- }
- break;
- }
- if (error) {
- viewHolder.time.setTextColor(0xFFe92727);
- } else {
- viewHolder.time.setTextColor(mSecondaryTextColor);
- }
- if (message.getEncryption() == Message.ENCRYPTION_NONE) {
- viewHolder.indicator.setVisibility(View.GONE);
- } else {
- viewHolder.indicator.setVisibility(View.VISIBLE);
- }
-
- String formatedTime = UIHelper.readableTimeDifference(
- getContext(), message.getTimeSent());
- if (message.getStatus() <= Message.STATUS_RECIEVED) {
- if ((filesize != null) && (info != null)) {
- viewHolder.time.setText(filesize + " \u00B7 " + info);
- } else if ((filesize == null) && (info != null)) {
- viewHolder.time.setText(formatedTime + " \u00B7 "
- + info);
- } else if ((filesize != null) && (info == null)) {
- viewHolder.time.setText(formatedTime + " \u00B7 "
- + filesize);
- } else {
- viewHolder.time.setText(formatedTime);
- }
- } else {
- if ((filesize != null) && (info != null)) {
- viewHolder.time.setText(filesize + " \u00B7 " + info);
- } else if ((filesize == null) && (info != null)) {
- if (error) {
- viewHolder.time.setText(info + " \u00B7 "
- + formatedTime);
- } else {
- viewHolder.time.setText(info);
- }
- } else if ((filesize != null) && (info == null)) {
- viewHolder.time.setText(filesize + " \u00B7 "
- + formatedTime);
- } else {
- viewHolder.time.setText(formatedTime);
- }
- }
- }
-
- private void displayInfoMessage(ViewHolder viewHolder, int r) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- viewHolder.messageBody.setText(getString(r));
- viewHolder.messageBody.setTextColor(0xff33B5E5);
- viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
- viewHolder.messageBody.setTextIsSelectable(false);
- }
-
- private void displayDecryptionFailed(ViewHolder viewHolder) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- viewHolder.messageBody
- .setText(getString(R.string.decryption_failed));
- viewHolder.messageBody.setTextColor(0xFFe92727);
- viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
- viewHolder.messageBody.setTextIsSelectable(false);
- }
-
- private void displayTextMessage(ViewHolder viewHolder, String text) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.VISIBLE);
- if (text != null) {
- viewHolder.messageBody.setText(text.trim());
- } else {
- viewHolder.messageBody.setText("");
- }
- viewHolder.messageBody.setTextColor(mPrimaryTextColor);
- viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
- viewHolder.messageBody.setTextIsSelectable(true);
- }
-
- private void displayImageMessage(ViewHolder viewHolder,
- final Message message) {
- if (viewHolder.download_button != null) {
- viewHolder.download_button.setVisibility(View.GONE);
- }
- viewHolder.messageBody.setVisibility(View.GONE);
- viewHolder.image.setVisibility(View.VISIBLE);
- String[] fileParams = message.getBody().split(",");
- if (fileParams.length == 3) {
- double target = metrics.density * 288;
- int w = Integer.parseInt(fileParams[1]);
- int h = Integer.parseInt(fileParams[2]);
- int scalledW;
- int scalledH;
- if (w <= h) {
- scalledW = (int) (w / ((double) h / target));
- scalledH = (int) target;
- } else {
- scalledW = (int) target;
- scalledH = (int) (h / ((double) w / target));
- }
- viewHolder.image
- .setLayoutParams(new LinearLayout.LayoutParams(
- scalledW, scalledH));
- }
- activity.loadBitmap(message, viewHolder.image);
- viewHolder.image.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(
- ImageProvider.getContentUri(message), "image/*");
- startActivity(intent);
- }
- });
- viewHolder.image
- .setOnLongClickListener(new OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- Intent shareIntent = new Intent();
- shareIntent.setAction(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_STREAM,
- ImageProvider.getContentUri(message));
- shareIntent.setType("image/webp");
- startActivity(Intent.createChooser(shareIntent,
- getText(R.string.share_with)));
- return true;
- }
- });
- }
-
+ messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
+ messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
+
@Override
- public View getView(int position, View view, ViewGroup parent) {
- final Message item = getItem(position);
- int type = getItemViewType(position);
- ViewHolder viewHolder;
- if (view == null) {
- viewHolder = new ViewHolder();
- switch (type) {
- case SENT:
- view = (View) inflater.inflate(R.layout.message_sent,
- null);
- viewHolder.message_box = (LinearLayout) view
- .findViewById(R.id.message_box);
- viewHolder.contact_picture = (ImageView) view
- .findViewById(R.id.message_photo);
- viewHolder.contact_picture.setImageBitmap(selfBitmap);
- viewHolder.indicator = (ImageView) view
- .findViewById(R.id.security_indicator);
- viewHolder.image = (ImageView) view
- .findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
- .findViewById(R.id.message_body);
- viewHolder.time = (TextView) view
- .findViewById(R.id.message_time);
- view.setTag(viewHolder);
- break;
- case RECIEVED:
- view = (View) inflater.inflate(
- R.layout.message_recieved, null);
- viewHolder.message_box = (LinearLayout) view
- .findViewById(R.id.message_box);
- viewHolder.contact_picture = (ImageView) view
- .findViewById(R.id.message_photo);
-
- viewHolder.download_button = (Button) view
- .findViewById(R.id.download_button);
-
- if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-
- viewHolder.contact_picture
- .setImageBitmap(mBitmapCache.get(
- item.getConversation().getName(
- useSubject), item
- .getConversation()
- .getContact(),
- getActivity()
- .getApplicationContext()));
-
- }
- viewHolder.indicator = (ImageView) view
- .findViewById(R.id.security_indicator);
- viewHolder.image = (ImageView) view
- .findViewById(R.id.message_image);
- viewHolder.messageBody = (TextView) view
- .findViewById(R.id.message_body);
- viewHolder.time = (TextView) view
- .findViewById(R.id.message_time);
- view.setTag(viewHolder);
- break;
- case STATUS:
- view = (View) inflater.inflate(R.layout.message_status,
- null);
- viewHolder.contact_picture = (ImageView) view
- .findViewById(R.id.message_photo);
- if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-
- viewHolder.contact_picture
- .setImageBitmap(mBitmapCache.get(
- item.getConversation().getName(
- useSubject), item
- .getConversation()
- .getContact(),
- getActivity()
- .getApplicationContext()));
- viewHolder.contact_picture.setAlpha(128);
-
- }
- break;
- default:
- viewHolder = null;
- break;
- }
- } else {
- viewHolder = (ViewHolder) view.getTag();
- }
-
- if (type == STATUS) {
- return view;
- }
-
- if (type == RECIEVED) {
- if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
- viewHolder.contact_picture.setImageBitmap(mBitmapCache
- .get(item.getCounterpart(), null, getActivity()
- .getApplicationContext()));
- viewHolder.contact_picture
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- highlightInConference(item
- .getCounterpart());
- }
- });
- }
+ public void onContactPictureClicked(Message message) {
+ if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+ highlightInConference(message.getCounterpart());
}
-
- if (item.getType() == Message.TYPE_IMAGE) {
- if (item.getStatus() == Message.STATUS_RECIEVING) {
- displayInfoMessage(viewHolder, R.string.receiving_image);
- } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
- viewHolder.image.setVisibility(View.GONE);
- viewHolder.messageBody.setVisibility(View.GONE);
- viewHolder.download_button.setVisibility(View.VISIBLE);
- viewHolder.download_button
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- JingleConnection connection = item
- .getJingleConnection();
- if (connection != null) {
- connection.accept();
- }
- }
- });
- } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
- || (item.getEncryption() == Message.ENCRYPTION_NONE)
- || (item.getEncryption() == Message.ENCRYPTION_OTR)) {
- displayImageMessage(viewHolder, item);
- } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
- displayInfoMessage(viewHolder,
- R.string.encrypted_message);
- } else {
- displayDecryptionFailed(viewHolder);
- }
- } else {
- if (item.getEncryption() == Message.ENCRYPTION_PGP) {
- if (activity.hasPgp()) {
- displayInfoMessage(viewHolder,
- R.string.encrypted_message);
- } else {
- displayInfoMessage(viewHolder,
- R.string.install_openkeychain);
- viewHolder.message_box
- .setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- activity.showInstallPgpDialog();
- }
- });
- }
- } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
- displayDecryptionFailed(viewHolder);
- } else {
- displayTextMessage(viewHolder, item.getBody());
- }
- }
-
- displayStatus(viewHolder, item);
-
- return view;
}
- };
+ });
messagesView.setAdapter(messageListAdapter);
return view;
@@ -582,17 +218,6 @@ public class ConversationFragment extends Fragment {
Selection.setSelection(etext, position);
}
- protected Bitmap findSelfPicture() {
- SharedPreferences sharedPref = PreferenceManager
- .getDefaultSharedPreferences(getActivity()
- .getApplicationContext());
- boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
- "show_phone_selfcontact_picture", true);
-
- return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
- showPhoneSelfContactPicture, getActivity());
- }
-
@Override
public void onStart() {
super.onStart();
@@ -633,7 +258,6 @@ public class ConversationFragment extends Fragment {
int position = chatMsg.length();
Editable etext = chatMsg.getText();
Selection.setSelection(etext, position);
- this.selfBitmap = findSelfPicture();
updateMessages();
if (activity.getSlidingPaneLayout().isSlideable()) {
if (!activity.shouldPaneBeOpen()) {
@@ -645,34 +269,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) {
@@ -683,7 +279,8 @@ public class ConversationFragment extends Fragment {
@Override
public void userInputRequried(PendingIntent pi, Message message) {
askForPassphraseIntent = pi.getIntentSender();
- showSnackbar(R.string.openpgp_messages_found,R.string.decrypt,clickToDecryptListener);
+ showSnackbar(R.string.openpgp_messages_found,
+ R.string.decrypt, clickToDecryptListener);
}
@Override
@@ -706,8 +303,20 @@ public class ConversationFragment extends Fragment {
if (getView() == null) {
return;
}
- ConversationActivity activity = (ConversationActivity) getActivity();
+ hideSnackbar();
+ final ConversationActivity activity = (ConversationActivity) getActivity();
if (this.conversation != null) {
+ final Contact contact = this.conversation.getContact();
+ if (!contact.showInRoster() && contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
+ showSnackbar(R.string.contact_added_you, R.string.add_back, new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.xmppConnectionService.createContact(contact);
+ activity.switchToContactDetails(contact);
+ }
+ });
+ }
for (Message message : this.conversation.getMessages()) {
if ((message.getEncryption() == Message.ENCRYPTION_PGP)
&& ((message.getStatus() == Message.STATUS_RECIEVED) || (message
@@ -734,10 +343,14 @@ public class ConversationFragment extends Fragment {
makeFingerprintWarning(conversation.getLatestEncryption());
}
} else {
- if (conversation.getMucOptions().getError() != 0) {
- showSnackbar(R.string.nick_in_use, R.string.edit,clickToMuc);
+ if (!conversation.getMucOptions().online()
+ && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
- showSnackbar(R.string.nick_in_use, R.string.edit,clickToMuc);
+ 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);
}
}
}
@@ -792,28 +405,31 @@ public class ConversationFragment extends Fragment {
&& (conversation.hasValidOtrSession()
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
.contains(conversation.getOtrFingerprint())))) {
- showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, 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,
- snackbar);
- dialog.show();
- }
- }
- });
+ @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) {
+
+ 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);
}
@@ -939,38 +555,6 @@ public class ConversationFragment extends Fragment {
}
}
- private static class ViewHolder {
-
- protected LinearLayout message_box;
- protected Button download_button;
- protected ImageView image;
- protected ImageView indicator;
- protected TextView time;
- protected TextView messageBody;
- protected ImageView contact_picture;
-
- }
-
- private class BitmapCache {
- private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
-
- public Bitmap get(String name, Contact contact, Context context) {
- if (bitmaps.containsKey(name)) {
- return bitmaps.get(name);
- } else {
- Bitmap bm;
- if (contact != null) {
- bm = UIHelper
- .getContactPicture(contact, 48, context, false);
- } else {
- bm = UIHelper.getContactPicture(name, 48, context, false);
- }
- bitmaps.put(name, bm);
- return bm;
- }
- }
- }
-
public void setText(String text) {
this.pastedText = text;
}
diff --git a/src/eu/siacs/conversations/ui/EditAccount.java b/src/eu/siacs/conversations/ui/EditAccountDialog.java
index 9a0b8d84..7c135fc1 100644
--- a/src/eu/siacs/conversations/ui/EditAccount.java
+++ b/src/eu/siacs/conversations/ui/EditAccountDialog.java
@@ -4,7 +4,7 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.utils.KnownHostsAdapter;
+import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.utils.Validator;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -21,7 +21,7 @@ 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;
diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
index c3f1e105..e56e2db9 100644
--- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java
+++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java
@@ -6,8 +6,7 @@ import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
-import eu.siacs.conversations.ui.EditAccount.EditAccountListener;
-import eu.siacs.conversations.xmpp.OnTLSExceptionReceived;
+import eu.siacs.conversations.ui.EditAccountDialog.EditAccountListener;
import eu.siacs.conversations.xmpp.XmppConnection;
import android.app.Activity;
import android.app.AlertDialog;
@@ -59,57 +58,6 @@ public class ManageAccountActivity extends XmppActivity {
}
};
- protected OnTLSExceptionReceived tlsExceptionReceived = new OnTLSExceptionReceived() {
-
- @Override
- public void onTLSExceptionReceived(final String fingerprint,
- final Account account) {
- activity.runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- 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);
- 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)) {
- humanReadableSha.insert(i, "\n");
- } else {
- humanReadableSha.insert(i, ":");
- }
-
- }
- 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.create().show();
- }
- });
-
- }
- };
-
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -172,11 +120,6 @@ public class ManageAccountActivity extends XmppActivity {
.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.setTextColor(0xFFe92727);
- break;
case Account.STATUS_REGISTRATION_FAILED:
statusView
.setText(getString(R.string.account_status_regis_fail));
@@ -214,14 +157,13 @@ 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)) {
+ if (account.getStatus() == Account.STATUS_OFFLINE) {
activity.xmppConnectionService.reconnectAccount(
accountList.get(position), true);
} else if (account.getStatus() == Account.STATUS_ONLINE) {
activity.startActivity(new Intent(activity
.getApplicationContext(),
- StartConversation.class));
+ StartConversationActivity.class));
} else if (account.getStatus() != Account.STATUS_DISABLED) {
editAccount(account);
}
@@ -471,7 +413,6 @@ public class ManageAccountActivity extends XmppActivity {
protected void onStop() {
if (xmppConnectionServiceBound) {
xmppConnectionService.removeOnAccountListChangedListener();
- xmppConnectionService.removeOnTLSExceptionReceivedListener();
}
super.onStop();
}
@@ -479,8 +420,6 @@ public class ManageAccountActivity extends XmppActivity {
@Override
void onBackendConnected() {
xmppConnectionService.setOnAccountListChangedListener(accountChanged);
- xmppConnectionService
- .setOnTLSExceptionReceivedListener(tlsExceptionReceived);
this.accountList.clear();
this.accountList.addAll(xmppConnectionService.getAccounts());
accountListViewAdapter.notifyDataSetChanged();
@@ -513,7 +452,7 @@ public class ManageAccountActivity extends XmppActivity {
@Override
public boolean onNavigateUp() {
if (xmppConnectionService.getConversations().size() == 0) {
- Intent contactsIntent = new Intent(this, StartConversation.class);
+ Intent contactsIntent = new Intent(this, StartConversationActivity.class);
contactsIntent.setFlags(
// if activity exists in stack, pop the stack and go back to it
Intent.FLAG_ACTIVITY_CLEAR_TOP |
@@ -531,7 +470,7 @@ public class ManageAccountActivity extends XmppActivity {
}
private void editAccount(Account account) {
- EditAccount dialog = new EditAccount();
+ EditAccountDialog dialog = new EditAccountDialog();
dialog.setAccount(account);
dialog.setEditAccountListener(new EditAccountListener() {
@@ -550,7 +489,7 @@ public class ManageAccountActivity extends XmppActivity {
protected void addAccount() {
final Activity activity = this;
- EditAccount dialog = new EditAccount();
+ EditAccountDialog dialog = new EditAccountDialog();
dialog.setEditAccountListener(new EditAccountListener() {
@Override
diff --git a/src/eu/siacs/conversations/ui/MucDetailsActivity.java b/src/eu/siacs/conversations/ui/MucDetailsActivity.java
deleted file mode 100644
index 8226e381..00000000
--- a/src/eu/siacs/conversations/ui/MucDetailsActivity.java
+++ /dev/null
@@ -1,214 +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 eu.siacs.conversations.xmpp.stanzas.MessagePacket;
-import android.app.PendingIntent;
-import android.content.Context;
-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())) {
- MessagePacket packet = xmppConnectionService.getMessageGenerator().conferenceSubject(conversation, subject);
- xmppConnectionService.sendMessagePacket(conversation.getAccount(), packet);
- 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/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/StartConversation.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java
index c9166c39..d12d2878 100644
--- a/src/eu/siacs/conversations/ui/StartConversation.java
+++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -12,6 +12,8 @@ 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;
@@ -19,11 +21,9 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
@@ -32,21 +32,20 @@ import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.CheckBox;
import android.widget.EditText;
-import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Spinner;
-import android.widget.TextView;
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.utils.KnownHostsAdapter;
-import eu.siacs.conversations.utils.UIHelper;
+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 StartConversation extends XmppActivity {
+public class StartConversationActivity extends XmppActivity {
private Tab mContactsTab;
private Tab mConferencesTab;
@@ -65,7 +64,7 @@ public class StartConversation extends XmppActivity {
private List<String> mKnownConferenceHosts;
private EditText mSearchEditText;
-
+
public int conference_context_id;
public int contact_context_id;
@@ -141,6 +140,19 @@ public class StartConversation extends XmppActivity {
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) {
@@ -175,19 +187,20 @@ public class StartConversation extends XmppActivity {
}
});
- mConferenceAdapter = new ListItemAdapter(conferences);
+ mConferenceAdapter = new ListItemAdapter(getApplicationContext(),conferences);
mConferenceListFragment.setListAdapter(mConferenceAdapter);
mConferenceListFragment.setContextMenu(R.menu.conference_context);
- mConferenceListFragment.setOnListItemClickListener(new OnItemClickListener() {
+ mConferenceListFragment
+ .setOnListItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1,
- int position, long arg3) {
- openConversationForBookmark(position);
- }
- });
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ openConversationForBookmark(position);
+ }
+ });
- mContactsAdapter = new ListItemAdapter(contacts);
+ mContactsAdapter = new ListItemAdapter(getApplicationContext(),contacts);
mContactsListFragment.setListAdapter(mContactsAdapter);
mContactsListFragment.setContextMenu(R.menu.contact_context);
mContactsListFragment
@@ -201,6 +214,12 @@ public class StartConversation extends XmppActivity {
});
}
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ xmppConnectionService.removeOnRosterUpdateListener();
+ }
protected void openConversationForContact(int position) {
Contact contact = (Contact) contacts.get(position);
@@ -209,20 +228,25 @@ public class StartConversation extends XmppActivity {
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 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());
@@ -238,18 +262,48 @@ public class StartConversation extends XmppActivity {
protected void deleteContact() {
int position = contact_context_id;
- Contact contact = (Contact) contacts.get(position);
- xmppConnectionService.deleteContactOnServer(contact);
- filter(mSearchEditText.getText().toString());
+ 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 = contact_context_id;
- Bookmark bookmark = (Bookmark) conferences.get(position);
- Account account = bookmark.getAccount();
- account.getBookmarks().remove(bookmark);
- xmppConnectionService.pushBookmarks(account);
- filter(mSearchEditText.getText().toString());
+ 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() {
@@ -307,7 +361,8 @@ public class StartConversation extends XmppActivity {
jid.setAdapter(new KnownHostsAdapter(this,
android.R.layout.simple_list_item_1, mKnownConferenceHosts));
populateAccountSpinner(spinner);
- final CheckBox bookmarkCheckBox = (CheckBox) dialogView.findViewById(R.id.bookmark);
+ final CheckBox bookmarkCheckBox = (CheckBox) dialogView
+ .findViewById(R.id.bookmark);
builder.setView(dialogView);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.join, null);
@@ -328,20 +383,28 @@ public class StartConversation extends XmppActivity {
if (account.hasBookmarkFor(conferenceJid)) {
jid.setError(getString(R.string.bookmark_already_exists));
} else {
- Bookmark bookmark = new Bookmark(account, conferenceJid);
+ Bookmark bookmark = new Bookmark(account,
+ conferenceJid);
bookmark.setAutojoin(true);
account.getBookmarks().add(bookmark);
- xmppConnectionService.pushBookmarks(account);
+ xmppConnectionService
+ .pushBookmarks(account);
Conversation conversation = xmppConnectionService
.findOrCreateConversation(account,
conferenceJid, true);
conversation.setBookmark(bookmark);
- switchToConversation(conversation);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
+ switchToConversation(conversation);
}
} else {
Conversation conversation = xmppConnectionService
- .findOrCreateConversation(account,
- conferenceJid, true);
+ .findOrCreateConversation(account,
+ conferenceJid, true);
+ if (!conversation.getMucOptions().online()) {
+ xmppConnectionService.joinMuc(conversation);
+ }
switchToConversation(conversation);
}
} else {
@@ -401,6 +464,7 @@ public class StartConversation extends XmppActivity {
@Override
void onBackendConnected() {
+ xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate );
if (mSearchEditText != null) {
filter(mSearchEditText.getText().toString());
} else {
@@ -416,7 +480,7 @@ public class StartConversation extends XmppActivity {
this.mKnownConferenceHosts = xmppConnectionService
.getKnownConferenceHosts();
}
-
+
protected void filter(String needle) {
this.filterContacts(needle);
this.filterConferences(needle);
@@ -436,12 +500,12 @@ public class StartConversation extends XmppActivity {
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()) {
+ for (Bookmark bookmark : account.getBookmarks()) {
if (bookmark.match(needle)) {
this.conferences.add(bookmark);
}
@@ -456,37 +520,10 @@ public class StartConversation extends XmppActivity {
invalidateOptionsMenu();
}
- private class ListItemAdapter extends ArrayAdapter<ListItem> {
-
- public ListItemAdapter(List<ListItem> objects) {
- super(getApplicationContext(), 0, objects);
- }
-
- @Override
- public View getView(int position, View view, ViewGroup parent) {
- LayoutInflater inflater = (LayoutInflater) 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, getApplicationContext()));
- return view;
- }
-
- }
-
public static class MyListFragment extends ListFragment {
private AdapterView.OnItemClickListener mOnItemClickListener;
private int mResContextMenu;
-
+
public void setContextMenu(int res) {
this.mResContextMenu = res;
}
@@ -512,9 +549,8 @@ public class StartConversation extends XmppActivity {
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
- StartConversation activity = (StartConversation) getActivity();
- activity.getMenuInflater().inflate(mResContextMenu,
- menu);
+ 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;
@@ -525,7 +561,7 @@ public class StartConversation extends XmppActivity {
@Override
public boolean onContextItemSelected(MenuItem item) {
- StartConversation activity = (StartConversation) getActivity();
+ StartConversationActivity activity = (StartConversationActivity) getActivity();
switch (item.getItemId()) {
case R.id.context_start_conversation:
activity.openConversationForContact();
diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java
index 217bae55..fad4d026 100644
--- a/src/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/eu/siacs/conversations/ui/XmppActivity.java
@@ -27,16 +27,29 @@ 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 int mPrimaryTextColor;
+ protected int mSecondaryTextColor;
+
+ protected interface OnValueEdited {
+ public void onValueEdited(String value);
+ }
+
+ public interface OnPresenceSelected {
+ public void onPresenceSelected();
+ }
protected ServiceConnection mConnection = new ServiceConnection() {
@@ -147,6 +160,8 @@ public abstract class XmppActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExceptionHelper.init(getApplicationContext());
+ mPrimaryTextColor = getResources().getColor(R.color.primarytext);
+ mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
}
public void switchToConversation(Conversation conversation) {
@@ -183,6 +198,12 @@ public abstract class XmppActivity extends Activity {
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>() {
@@ -193,10 +214,7 @@ 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
@@ -251,11 +269,32 @@ public abstract class XmppActivity extends Activity {
Account account = conversation.getAccount();
Contact contact = account.getRoster().getContact(jid);
xmppConnectionService.createContact(contact);
+ switchToContactDetails(contact);
}
});
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) {
Contact contact = conversation.getContact();
@@ -307,4 +346,26 @@ 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.invite(conversation, contactJid);
+ }
+ Log.d("xmppService","inviting "+contactJid+" to "+conversation.getName(true));
+ }
+ }
+
+ public int getSecondaryTextColor() {
+ return this.mSecondaryTextColor;
+ }
+
+ public int getPrimaryTextColor() {
+ return this.mPrimaryTextColor;
+ }
}
diff --git a/src/eu/siacs/conversations/utils/KnownHostsAdapter.java b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
index a0a223dd..040e6266 100644
--- a/src/eu/siacs/conversations/utils/KnownHostsAdapter.java
+++ b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java
@@ -1,4 +1,4 @@
-package eu.siacs.conversations.utils;
+package eu.siacs.conversations.ui.adapter;
import java.util.ArrayList;
import java.util.List;
@@ -42,7 +42,7 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
- ArrayList<String> filteredList = ((ArrayList<String>) results.values);
+ ArrayList<String> filteredList = (ArrayList<String>) results.values;
if (results != null && results.count > 0) {
clear();
for (String c : filteredList) {
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/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
new file mode 100644
index 00000000..0a2857d2
--- /dev/null
+++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -0,0 +1,478 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.HashMap;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+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.ui.ConversationActivity;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jingle.JingleConnection;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MessageAdapter extends ArrayAdapter<Message> {
+
+ private static final int SENT = 0;
+ private static final int RECIEVED = 1;
+ private static final int STATUS = 2;
+
+ private ConversationActivity activity;
+
+ private Bitmap selfBitmap2;
+
+ private BitmapCache mBitmapCache = new BitmapCache();
+ private DisplayMetrics metrics;
+
+ private boolean useSubject = true;
+
+ private OnContactPictureClicked mOnContactPictureClickedListener;
+
+ public MessageAdapter(ConversationActivity activity, List<Message> messages) {
+ super(activity, 0, messages);
+ this.activity = activity;
+ metrics = getContext().getResources().getDisplayMetrics();
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getContext());
+ useSubject = preferences.getBoolean("use_subject_in_muc", true);
+ }
+
+ private Bitmap getSelfBitmap() {
+ if (this.selfBitmap2 == null) {
+
+ if (getCount() > 0) {
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getContext());
+ boolean showPhoneSelfContactPicture = preferences.getBoolean(
+ "show_phone_selfcontact_picture", true);
+
+ this.selfBitmap2 = UIHelper.getSelfContactPicture(getItem(0)
+ .getConversation().getAccount(), 48,
+ showPhoneSelfContactPicture, getContext());
+ }
+ }
+ return this.selfBitmap2;
+ }
+
+ public void setOnContactPictureClicked(OnContactPictureClicked listener) {
+ this.mOnContactPictureClickedListener = listener;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 3;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (getItem(position).getType() == Message.TYPE_STATUS) {
+ return STATUS;
+ } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
+ return RECIEVED;
+ } else {
+ return SENT;
+ }
+ }
+
+ private void displayStatus(ViewHolder viewHolder, Message message) {
+ String filesize = null;
+ String info = null;
+ boolean error = false;
+ boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
+ && message.getStatus() <= Message.STATUS_RECIEVED;
+ if (message.getType() == Message.TYPE_IMAGE) {
+ String[] fileParams = message.getBody().split(",");
+ try {
+ long size = Long.parseLong(fileParams[0]);
+ filesize = size / 1024 + " KB";
+ } catch (NumberFormatException e) {
+ filesize = "0 KB";
+ }
+ }
+ switch (message.getStatus()) {
+ case Message.STATUS_WAITING:
+ info = getContext().getString(R.string.waiting);
+ break;
+ case Message.STATUS_UNSEND:
+ info = getContext().getString(R.string.sending);
+ break;
+ case Message.STATUS_OFFERED:
+ info = getContext().getString(R.string.offering);
+ break;
+ case Message.STATUS_SEND_FAILED:
+ info = getContext().getString(R.string.send_failed);
+ error = true;
+ break;
+ case Message.STATUS_SEND_REJECTED:
+ info = getContext().getString(R.string.send_rejected);
+ error = true;
+ break;
+ case Message.STATUS_RECEPTION_FAILED:
+ info = getContext().getString(R.string.reception_failed);
+ error = true;
+ default:
+ if (multiReceived) {
+ info = message.getCounterpart();
+ }
+ break;
+ }
+ if (error) {
+ viewHolder.time.setTextColor(0xFFe92727);
+ } else {
+ viewHolder.time.setTextColor(activity.getSecondaryTextColor());
+ }
+ if (message.getEncryption() == Message.ENCRYPTION_NONE) {
+ viewHolder.indicator.setVisibility(View.GONE);
+ } else {
+ viewHolder.indicator.setVisibility(View.VISIBLE);
+ }
+
+ String formatedTime = UIHelper.readableTimeDifference(getContext(),
+ message.getTimeSent());
+ if (message.getStatus() <= Message.STATUS_RECIEVED) {
+ if ((filesize != null) && (info != null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + info);
+ } else if ((filesize == null) && (info != null)) {
+ viewHolder.time.setText(formatedTime + " \u00B7 " + info);
+ } else if ((filesize != null) && (info == null)) {
+ viewHolder.time.setText(formatedTime + " \u00B7 " + filesize);
+ } else {
+ viewHolder.time.setText(formatedTime);
+ }
+ } else {
+ if ((filesize != null) && (info != null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + info);
+ } else if ((filesize == null) && (info != null)) {
+ if (error) {
+ viewHolder.time.setText(info + " \u00B7 " + formatedTime);
+ } else {
+ viewHolder.time.setText(info);
+ }
+ } else if ((filesize != null) && (info == null)) {
+ viewHolder.time.setText(filesize + " \u00B7 " + formatedTime);
+ } else {
+ viewHolder.time.setText(formatedTime);
+ }
+ }
+ }
+
+ private void displayInfoMessage(ViewHolder viewHolder, int r) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ viewHolder.messageBody.setText(getContext().getString(r));
+ viewHolder.messageBody.setTextColor(0xff33B5E5);
+ viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
+ viewHolder.messageBody.setTextIsSelectable(false);
+ }
+
+ private void displayDecryptionFailed(ViewHolder viewHolder) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ viewHolder.messageBody.setText(getContext().getString(
+ R.string.decryption_failed));
+ viewHolder.messageBody.setTextColor(0xFFe92727);
+ viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+ viewHolder.messageBody.setTextIsSelectable(false);
+ }
+
+ private void displayTextMessage(ViewHolder viewHolder, String text) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.VISIBLE);
+ if (text != null) {
+ viewHolder.messageBody.setText(text.trim());
+ } else {
+ viewHolder.messageBody.setText("");
+ }
+ viewHolder.messageBody.setTextColor(activity.getPrimaryTextColor());
+ viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+ viewHolder.messageBody.setTextIsSelectable(true);
+ }
+
+ private void displayImageMessage(ViewHolder viewHolder,
+ final Message message) {
+ if (viewHolder.download_button != null) {
+ viewHolder.download_button.setVisibility(View.GONE);
+ }
+ viewHolder.messageBody.setVisibility(View.GONE);
+ viewHolder.image.setVisibility(View.VISIBLE);
+ String[] fileParams = message.getBody().split(",");
+ if (fileParams.length == 3) {
+ double target = metrics.density * 288;
+ int w = Integer.parseInt(fileParams[1]);
+ int h = Integer.parseInt(fileParams[2]);
+ int scalledW;
+ int scalledH;
+ if (w <= h) {
+ scalledW = (int) (w / ((double) h / target));
+ scalledH = (int) target;
+ } else {
+ scalledW = (int) target;
+ scalledH = (int) (h / ((double) w / target));
+ }
+ viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams(
+ scalledW, scalledH));
+ }
+ activity.loadBitmap(message, viewHolder.image);
+ viewHolder.image.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setDataAndType(ImageProvider.getContentUri(message),
+ "image/*");
+ getContext().startActivity(intent);
+ }
+ });
+ viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ Intent shareIntent = new Intent();
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.putExtra(Intent.EXTRA_STREAM,
+ ImageProvider.getContentUri(message));
+ shareIntent.setType("image/webp");
+ getContext().startActivity(
+ Intent.createChooser(shareIntent,
+ getContext().getText(R.string.share_with)));
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ final Message item = getItem(position);
+ int type = getItemViewType(position);
+ ViewHolder viewHolder;
+ if (view == null) {
+ viewHolder = new ViewHolder();
+ switch (type) {
+ case SENT:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_sent, null);
+ viewHolder.message_box = (LinearLayout) view
+ .findViewById(R.id.message_box);
+ viewHolder.contact_picture = (ImageView) view
+ .findViewById(R.id.message_photo);
+ viewHolder.contact_picture.setImageBitmap(getSelfBitmap());
+ viewHolder.indicator = (ImageView) view
+ .findViewById(R.id.security_indicator);
+ viewHolder.image = (ImageView) view
+ .findViewById(R.id.message_image);
+ viewHolder.messageBody = (TextView) view
+ .findViewById(R.id.message_body);
+ viewHolder.time = (TextView) view
+ .findViewById(R.id.message_time);
+ view.setTag(viewHolder);
+ break;
+ case RECIEVED:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_recieved, null);
+ viewHolder.message_box = (LinearLayout) view
+ .findViewById(R.id.message_box);
+ viewHolder.contact_picture = (ImageView) view
+ .findViewById(R.id.message_photo);
+
+ viewHolder.download_button = (Button) view
+ .findViewById(R.id.download_button);
+
+ if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ item.getConversation().getName(useSubject), item
+ .getConversation().getContact(),
+ getContext()));
+
+ }
+ viewHolder.indicator = (ImageView) view
+ .findViewById(R.id.security_indicator);
+ viewHolder.image = (ImageView) view
+ .findViewById(R.id.message_image);
+ viewHolder.messageBody = (TextView) view
+ .findViewById(R.id.message_body);
+ viewHolder.time = (TextView) view
+ .findViewById(R.id.message_time);
+ view.setTag(viewHolder);
+ break;
+ case STATUS:
+ view = (View) activity.getLayoutInflater().inflate(
+ R.layout.message_status, null);
+ viewHolder.contact_picture = (ImageView) view
+ .findViewById(R.id.message_photo);
+ if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ item.getConversation().getName(useSubject), item
+ .getConversation().getContact(),
+ getContext()));
+ viewHolder.contact_picture.setAlpha(128);
+ viewHolder.contact_picture
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ String name = item.getConversation()
+ .getName(true);
+ String read = getContext()
+ .getString(
+ R.string.contact_has_read_up_to_this_point,
+ name);
+ Toast.makeText(getContext(), read,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ }
+ break;
+ default:
+ viewHolder = null;
+ break;
+ }
+ } else {
+ viewHolder = (ViewHolder) view.getTag();
+ }
+
+ if (type == STATUS) {
+ return view;
+ }
+
+ if (type == RECIEVED) {
+ if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
+ viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+ item.getCounterpart(), null, getContext()));
+ viewHolder.contact_picture
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
+ MessageAdapter.this.mOnContactPictureClickedListener
+ .onContactPictureClicked(item);
+ ;
+ }
+
+ }
+ });
+ }
+ }
+
+ if (item.getType() == Message.TYPE_IMAGE) {
+ if (item.getStatus() == Message.STATUS_RECIEVING) {
+ displayInfoMessage(viewHolder, R.string.receiving_image);
+ } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
+ viewHolder.image.setVisibility(View.GONE);
+ viewHolder.messageBody.setVisibility(View.GONE);
+ viewHolder.download_button.setVisibility(View.VISIBLE);
+ viewHolder.download_button
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ JingleConnection connection = item
+ .getJingleConnection();
+ if (connection != null) {
+ connection.accept();
+ }
+ }
+ });
+ } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
+ || (item.getEncryption() == Message.ENCRYPTION_NONE)
+ || (item.getEncryption() == Message.ENCRYPTION_OTR)) {
+ displayImageMessage(viewHolder, item);
+ } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+ displayInfoMessage(viewHolder, R.string.encrypted_message);
+ } else {
+ displayDecryptionFailed(viewHolder);
+ }
+ } else {
+ if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+ if (activity.hasPgp()) {
+ displayInfoMessage(viewHolder, R.string.encrypted_message);
+ } else {
+ displayInfoMessage(viewHolder,
+ R.string.install_openkeychain);
+ viewHolder.message_box
+ .setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ activity.showInstallPgpDialog();
+ }
+ });
+ }
+ } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
+ displayDecryptionFailed(viewHolder);
+ } else {
+ displayTextMessage(viewHolder, item.getBody());
+ }
+ }
+
+ displayStatus(viewHolder, item);
+
+ return view;
+ }
+
+ private static class ViewHolder {
+
+ protected LinearLayout message_box;
+ protected Button download_button;
+ protected ImageView image;
+ protected ImageView indicator;
+ protected TextView time;
+ protected TextView messageBody;
+ protected ImageView contact_picture;
+
+ }
+
+ private class BitmapCache {
+ private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
+
+ public Bitmap get(String name, Contact contact, Context context) {
+ if (bitmaps.containsKey(name)) {
+ return bitmaps.get(name);
+ } else {
+ Bitmap bm;
+ if (contact != null) {
+ bm = UIHelper
+ .getContactPicture(contact, 48, context, false);
+ } else {
+ bm = UIHelper.getContactPicture(name, 48, context, false);
+ }
+ bitmaps.put(name, bm);
+ return bm;
+ }
+ }
+ }
+
+ public interface OnContactPictureClicked {
+ public void onContactPictureClicked(Message message);
+ }
+}
diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java
index ede43830..1cd3403c 100644
--- a/src/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/eu/siacs/conversations/utils/UIHelper.java
@@ -13,7 +13,6 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
-import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions.User;
import eu.siacs.conversations.ui.ConversationActivity;
@@ -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()) {
diff --git a/src/eu/siacs/conversations/utils/Validator.java b/src/eu/siacs/conversations/utils/Validator.java
index 51d8b25c..9ca1e34f 100644
--- a/src/eu/siacs/conversations/utils/Validator.java
+++ b/src/eu/siacs/conversations/utils/Validator.java
@@ -5,7 +5,7 @@ import java.util.regex.Pattern;
public class Validator {
public static final Pattern VALID_JID =
- Pattern.compile("\\b^[A-Z0-9._%+-]+@([A-Z0-9.-]+\\.)?\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}[.]\\d{1,3}\\b$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
+ Pattern.compile("\\b^[^@/<>'\"\\s]+@[^@/<>'\"\\s]+$", Pattern.CASE_INSENSITIVE);
public static boolean isValidJid(String jid) {
Matcher matcher = VALID_JID.matcher(jid);
diff --git a/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java b/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java
deleted file mode 100644
index 0e232ee4..00000000
--- a/src/eu/siacs/conversations/xmpp/OnTLSExceptionReceived.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package eu.siacs.conversations.xmpp;
-
-import eu.siacs.conversations.entities.Account;
-
-public interface OnTLSExceptionReceived {
- public void onTLSExceptionReceived(String fingerprint, Account account);
-}
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java
index 72018394..45bac2f6 100644
--- a/src/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -21,6 +21,7 @@ import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
+import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
@@ -28,8 +29,12 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
+import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe;
import org.xmlpull.v1.XmlPullParserException;
+import de.duenndns.ssl.MemorizingTrustManager;
+
+import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -97,11 +102,12 @@ public class XmppConnection implements Runnable {
private OnIqPacketReceived unregisteredIqListener = null;
private OnMessagePacketReceived messageListener = null;
private OnStatusChanged statusListener = null;
- private OnTLSExceptionReceived tlsListener = null;
private OnBindListener bindListener = null;
+ private MemorizingTrustManager mMemorizingTrustManager;
public XmppConnection(Account account, XmppConnectionService service) {
this.mRandom = service.getRNG();
+ this.mMemorizingTrustManager = service.getMemorizingTrustManager();
this.account = account;
this.wakeLock = service.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
account.getJid());
@@ -186,9 +192,7 @@ public class XmppConnection implements Runnable {
}
return;
} catch (IOException e) {
- if (account.getStatus() != Account.STATUS_TLS_ERROR) {
- this.changeStatus(Account.STATUS_OFFLINE);
- }
+ this.changeStatus(Account.STATUS_OFFLINE);
if (wakeLock.isHeld()) {
try { wakeLock.release();} catch (RuntimeException re) {}
}
@@ -440,67 +444,19 @@ public class XmppConnection implements Runnable {
tagReader.readTag();
try {
SSLContext sc = SSLContext.getInstance("TLS");
- TrustManagerFactory tmf = TrustManagerFactory
- .getInstance(TrustManagerFactory.getDefaultAlgorithm());
- try {
- tmf.init((KeyStore) null);
- } catch (KeyStoreException e1) {
- e1.printStackTrace();
- }
-
- TrustManager[] trustManagers = tmf.getTrustManagers();
- final X509TrustManager origTrustmanager = (X509TrustManager) trustManagers[0];
-
- TrustManager[] wrappedTrustManagers = new TrustManager[] { new X509TrustManager() {
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- origTrustmanager.checkClientTrusted(chain, authType);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- try {
- origTrustmanager.checkServerTrusted(chain, authType);
- } catch (CertificateException e) {
- if (e.getCause() instanceof CertPathValidatorException) {
- String sha;
- try {
- MessageDigest sha1 = MessageDigest
- .getInstance("SHA1");
- sha1.update(chain[0].getEncoded());
- sha = CryptoHelper.bytesToHex(sha1.digest());
- if (!sha.equals(account.getSSLFingerprint())) {
- changeStatus(Account.STATUS_TLS_ERROR);
- if (tlsListener != null) {
- tlsListener.onTLSExceptionReceived(sha,
- account);
- }
- throw new CertificateException();
- }
- } catch (NoSuchAlgorithmException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
- } else {
- throw new CertificateException();
- }
- }
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return origTrustmanager.getAcceptedIssuers();
- }
-
- } };
- sc.init(null, wrappedTrustManagers, null);
+ sc.init(null, new X509TrustManager[] { this.mMemorizingTrustManager }, mRandom);
SSLSocketFactory factory = sc.getSocketFactory();
+
+ HostnameVerifier verifier = this.mMemorizingTrustManager.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier());
SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket,
socket.getInetAddress().getHostAddress(), socket.getPort(),
true);
+
+ if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) {
+ Log.d(LOGTAG, account.getJid() + ": host mismatch in TLS connection");
+ sslSocket.close();
+ throw new IOException();
+ }
tagReader.setInputStream(sslSocket.getInputStream());
tagWriter.setOutputStream(sslSocket.getOutputStream());
sendStartStream();
@@ -508,10 +464,8 @@ public class XmppConnection implements Runnable {
processStream(tagReader.readTag());
sslSocket.close();
} catch (NoSuchAlgorithmException e1) {
- // TODO Auto-generated catch block
e1.printStackTrace();
} catch (KeyManagementException e) {
- // TODO Auto-generated catch block
e.printStackTrace();
}
}
@@ -844,11 +798,6 @@ public class XmppConnection implements Runnable {
this.statusListener = listener;
}
- public void setOnTLSExceptionReceivedListener(
- OnTLSExceptionReceived listener) {
- this.tlsListener = listener;
- }
-
public void setOnBindListener(OnBindListener listener) {
this.bindListener = listener;
}