diff options
Diffstat (limited to 'src')
28 files changed, 236 insertions, 118 deletions
diff --git a/src/eu/siacs/conversations/crypto/OtrEngine.java b/src/eu/siacs/conversations/crypto/OtrEngine.java index 5dfd6fd6..e0bd0e79 100644 --- a/src/eu/siacs/conversations/crypto/OtrEngine.java +++ b/src/eu/siacs/conversations/crypto/OtrEngine.java @@ -18,8 +18,6 @@ import android.util.Log; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Conversation; -import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; @@ -29,8 +27,6 @@ import net.java.otr4j.OtrPolicy; import net.java.otr4j.OtrPolicyImpl; import net.java.otr4j.session.InstanceTag; import net.java.otr4j.session.SessionID; -import net.java.otr4j.session.SessionImpl; -import net.java.otr4j.session.SessionStatus; public class OtrEngine implements OtrEngineHost { diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java index 005b83db..8395449d 100644 --- a/src/eu/siacs/conversations/entities/Conversation.java +++ b/src/eu/siacs/conversations/entities/Conversation.java @@ -230,7 +230,7 @@ public class Conversation extends AbstractEntity { return this.otrSession; } else { SessionID sessionId = new SessionID( - this.getContactJid().split("/")[0], presence, "xmpp"); + this.getContactJid().split("/",2)[0], presence, "xmpp"); this.otrSession = new SessionImpl(sessionId, getAccount() .getOtrEngine(service)); try { diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java index ce496d27..8f9885c5 100644 --- a/src/eu/siacs/conversations/entities/Message.java +++ b/src/eu/siacs/conversations/entities/Message.java @@ -246,9 +246,10 @@ public class Message extends AbstractEntity { public void setPresence(String presence) { if (presence == null) { - this.counterpart = this.counterpart.split("/")[0]; + this.counterpart = this.counterpart.split("/", 2)[0]; } else { - this.counterpart = this.counterpart.split("/")[0] + "/" + presence; + this.counterpart = this.counterpart.split("/", 2)[0] + "/" + + presence; } } @@ -257,7 +258,7 @@ public class Message extends AbstractEntity { } public String getPresence() { - String[] counterparts = this.counterpart.split("/"); + String[] counterparts = this.counterpart.split("/", 2); if (counterparts.length == 2) { return counterparts[1]; } else { @@ -327,11 +328,11 @@ public class Message extends AbstractEntity { && this.getEncryption() == message.getEncryption() && this.getCounterpart().equals(message.getCounterpart()) && (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && ((this - .getStatus() == message.getStatus()) || ((this.getStatus() == Message.STATUS_SEND || this + .getStatus() == message.getStatus() || ((this.getStatus() == Message.STATUS_SEND || this .getStatus() == Message.STATUS_SEND_RECEIVED) && (message .getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_SEND || message - .getStatus() == Message.STATUS_SEND_DISPLAYED)))); + .getStatus() == Message.STATUS_SEND_DISPLAYED))))); } public String getMergedBody() { diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java index e9ab6908..676fb4f4 100644 --- a/src/eu/siacs/conversations/entities/MucOptions.java +++ b/src/eu/siacs/conversations/entities/MucOptions.java @@ -134,7 +134,7 @@ public class MucOptions { } public void processPacket(PresencePacket packet, PgpEngine pgp) { - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); if (fromParts.length >= 2) { String name = fromParts[1]; String type = packet.getAttribute("type"); @@ -180,7 +180,7 @@ public class MucOptions { } } } else if (type.equals("unavailable")) { - deleteUser(packet.getAttribute("from").split("/")[1]); + deleteUser(packet.getAttribute("from").split("/",2)[1]); } else if (type.equals("error")) { Element error = packet.findChild("error"); if (error.hasChild("conflict")) { @@ -209,7 +209,7 @@ public class MucOptions { } public String getProposedNick() { - String[] mucParts = conversation.getContactJid().split("/"); + String[] mucParts = conversation.getContactJid().split("/",2); if (conversation.getBookmark() != null && conversation.getBookmark().getNick() != null) { return conversation.getBookmark().getNick(); @@ -309,7 +309,7 @@ public class MucOptions { } public String getJoinJid() { - return this.conversation.getContactJid().split("/")[0] + "/" + return this.conversation.getContactJid().split("/",2)[0] + "/" + this.joinnick; } diff --git a/src/eu/siacs/conversations/entities/Roster.java b/src/eu/siacs/conversations/entities/Roster.java index c6212f77..f11f0250 100644 --- a/src/eu/siacs/conversations/entities/Roster.java +++ b/src/eu/siacs/conversations/entities/Roster.java @@ -15,12 +15,12 @@ public class Roster { } public boolean hasContact(String jid) { - String cleanJid = jid.split("/")[0]; + String cleanJid = jid.split("/",2)[0]; return contacts.containsKey(cleanJid); } public Contact getContact(String jid) { - String cleanJid = jid.split("/")[0].toLowerCase(Locale.getDefault()); + String cleanJid = jid.split("/",2)[0].toLowerCase(Locale.getDefault()); if (contacts.containsKey(cleanJid)) { return contacts.get(cleanJid); } else { diff --git a/src/eu/siacs/conversations/generator/AbstractGenerator.java b/src/eu/siacs/conversations/generator/AbstractGenerator.java index 05d3d988..61f290e4 100644 --- a/src/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/eu/siacs/conversations/generator/AbstractGenerator.java @@ -6,6 +6,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.services.XmppConnectionService; + import android.util.Base64; public abstract class AbstractGenerator { @@ -19,6 +21,12 @@ public abstract class AbstractGenerator { "urn:xmpp:avatar:metadata+notify" }; public final String IDENTITY_NAME = "Conversations 0.7"; public final String IDENTITY_TYPE = "phone"; + + protected XmppConnectionService mXmppConnectionService; + + protected AbstractGenerator(XmppConnectionService service) { + this.mXmppConnectionService = service; + } public String getCapHash() { StringBuilder s = new StringBuilder(); diff --git a/src/eu/siacs/conversations/generator/IqGenerator.java b/src/eu/siacs/conversations/generator/IqGenerator.java index b5ecafb5..d44bf0ca 100644 --- a/src/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/eu/siacs/conversations/generator/IqGenerator.java @@ -4,12 +4,17 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class IqGenerator extends AbstractGenerator { + public IqGenerator(XmppConnectionService service) { + super(service); + } + public IqPacket discoResponse(IqPacket request) { IqPacket packet = new IqPacket(IqPacket.TYPE_RESULT); packet.setId(request.getId()); diff --git a/src/eu/siacs/conversations/generator/MessageGenerator.java b/src/eu/siacs/conversations/generator/MessageGenerator.java index ecfb4744..d4cab3ed 100644 --- a/src/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/eu/siacs/conversations/generator/MessageGenerator.java @@ -10,10 +10,15 @@ import net.java.otr4j.session.Session; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; -public class MessageGenerator { +public class MessageGenerator extends AbstractGenerator { + public MessageGenerator(XmppConnectionService service) { + super(service); + } + private MessagePacket preparePacket(Message message, boolean addDelay) { Conversation conversation = message.getConversation(); Account account = conversation.getAccount(); @@ -22,11 +27,14 @@ public class MessageGenerator { packet.setTo(message.getCounterpart()); packet.setType(MessagePacket.TYPE_CHAT); packet.addChild("markable", "urn:xmpp:chat-markers:0"); + if (this.mXmppConnectionService.indicateReceived()) { + packet.addChild("request", "urn:xmpp:receipts"); + } } else if (message.getType() == Message.TYPE_PRIVATE) { packet.setTo(message.getCounterpart()); packet.setType(MessagePacket.TYPE_CHAT); } else { - packet.setTo(message.getCounterpart().split("/")[0]); + packet.setTo(message.getCounterpart().split("/",2)[0]); packet.setType(MessagePacket.TYPE_GROUPCHAT); } packet.setFrom(account.getFullJid()); @@ -126,7 +134,7 @@ public class MessageGenerator { String subject) { MessagePacket packet = new MessagePacket(); packet.setType(MessagePacket.TYPE_GROUPCHAT); - packet.setTo(conversation.getContactJid().split("/")[0]); + packet.setTo(conversation.getContactJid().split("/",2)[0]); Element subjectChild = new Element("subject"); subjectChild.setContent(subject); packet.addChild(subjectChild); @@ -140,13 +148,13 @@ public class MessageGenerator { packet.setTo(contact); packet.setFrom(conversation.getAccount().getFullJid()); Element x = packet.addChild("x", "jabber:x:conference"); - x.setAttribute("jid", conversation.getContactJid().split("/")[0]); + x.setAttribute("jid", conversation.getContactJid().split("/",2)[0]); return packet; } public MessagePacket invite(Conversation conversation, String contact) { MessagePacket packet = new MessagePacket(); - packet.setTo(conversation.getContactJid().split("/")[0]); + packet.setTo(conversation.getContactJid().split("/",2)[0]); packet.setFrom(conversation.getAccount().getFullJid()); Element x = new Element("x"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); diff --git a/src/eu/siacs/conversations/generator/PresenceGenerator.java b/src/eu/siacs/conversations/generator/PresenceGenerator.java index 87e361f5..d896dd00 100644 --- a/src/eu/siacs/conversations/generator/PresenceGenerator.java +++ b/src/eu/siacs/conversations/generator/PresenceGenerator.java @@ -2,11 +2,16 @@ package eu.siacs.conversations.generator; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; public class PresenceGenerator extends AbstractGenerator { + public PresenceGenerator(XmppConnectionService service) { + super(service); + } + private PresencePacket subscription(String type, Contact contact) { PresencePacket packet = new PresencePacket(); packet.setAttribute("type", type); diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java index 25fcd921..efbf5aef 100644 --- a/src/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/eu/siacs/conversations/parser/AbstractParser.java @@ -60,7 +60,7 @@ public abstract class AbstractParser { protected void updateLastseen(Element packet, Account account, boolean presenceOverwrite) { - String[] fromParts = packet.getAttribute("from").split("/"); + String[] fromParts = packet.getAttribute("from").split("/",2); String from = fromParts[0]; String presence = null; if (fromParts.length >= 2) { diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index 534c9dea..0e15c60f 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/src/eu/siacs/conversations/parser/MessageParser.java @@ -25,7 +25,7 @@ public class MessageParser extends AbstractParser implements } private Message parseChat(MessagePacket packet, Account account) { - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); @@ -57,9 +57,9 @@ public class MessageParser extends AbstractParser implements } private Message parseOtrChat(MessagePacket packet, Account account) { - boolean properlyAddressed = (packet.getTo().split("/").length == 2) + boolean properlyAddressed = (packet.getTo().split("/",2).length == 2) || (account.countPresences() == 1); - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); String presence; @@ -132,7 +132,7 @@ public class MessageParser extends AbstractParser implements private Message parseGroupchat(MessagePacket packet, Account account) { int status; - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); if (mXmppConnectionService.find(account.pendingConferenceLeaves, account, fromParts[0]) != null) { return null; @@ -186,11 +186,13 @@ public class MessageParser extends AbstractParser implements int status; String fullJid; Element forwarded; - if (packet.hasChild("received")) { - forwarded = packet.findChild("received").findChild("forwarded"); + if (packet.hasChild("received", "urn:xmpp:carbons:2")) { + forwarded = packet.findChild("received", "urn:xmpp:carbons:2") + .findChild("forwarded", "urn:xmpp:forward:0"); status = Message.STATUS_RECEIVED; - } else if (packet.hasChild("sent")) { - forwarded = packet.findChild("sent").findChild("forwarded"); + } else if (packet.hasChild("sent", "urn:xmpp:carbons:2")) { + forwarded = packet.findChild("sent", "urn:xmpp:carbons:2") + .findChild("forwarded", "urn:xmpp:forward:0"); status = Message.STATUS_SEND; } else { return null; @@ -219,7 +221,7 @@ public class MessageParser extends AbstractParser implements return null; } } - String[] parts = fullJid.split("/"); + String[] parts = fullJid.split("/",2); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, parts[0], false); conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); @@ -251,7 +253,7 @@ public class MessageParser extends AbstractParser implements } private void parseError(MessagePacket packet, Account account) { - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); mXmppConnectionService.markMessage(account, fromParts[0], packet.getId(), Message.STATUS_SEND_FAILED); } @@ -265,13 +267,20 @@ public class MessageParser extends AbstractParser implements String id = packet .findChild("displayed", "urn:xmpp:chat-markers:0") .getAttribute("id"); - String[] fromParts = packet.getAttribute("from").split("/"); + String[] fromParts = packet.getAttribute("from").split("/",2); updateLastseen(packet, account, true); mXmppConnectionService.markMessage(account, fromParts[0], id, Message.STATUS_SEND_DISPLAYED); } else if (packet.hasChild("received", "urn:xmpp:chat-markers:0")) { String id = packet.findChild("received", "urn:xmpp:chat-markers:0") .getAttribute("id"); + String[] fromParts = packet.getAttribute("from").split("/",2); + updateLastseen(packet, account, false); + mXmppConnectionService.markMessage(account, fromParts[0], id, + Message.STATUS_SEND_RECEIVED); + } else if (packet.hasChild("received", "urn:xmpp:receipts")) { + String id = packet.findChild("received", "urn:xmpp:receipts") + .getAttribute("id"); String[] fromParts = packet.getAttribute("from").split("/"); updateLastseen(packet, account, false); mXmppConnectionService.markMessage(account, fromParts[0], id, @@ -392,7 +401,8 @@ public class MessageParser extends AbstractParser implements if (message != null) { message.markUnread(); } - } else if (packet.hasChild("received") || (packet.hasChild("sent"))) { + } else if (packet.hasChild("received", "urn:xmpp:carbons:2") + || (packet.hasChild("sent", "urn:xmpp:carbons:2"))) { message = this.parseCarbonMessage(packet, account); if (message != null) { if (message.getStatus() == Message.STATUS_SEND) { diff --git a/src/eu/siacs/conversations/parser/PresenceParser.java b/src/eu/siacs/conversations/parser/PresenceParser.java index 05ffa67e..e240a858 100644 --- a/src/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/eu/siacs/conversations/parser/PresenceParser.java @@ -22,7 +22,7 @@ public class PresenceParser extends AbstractParser implements PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine(); if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) { Conversation muc = mXmppConnectionService.find(account, packet - .getAttribute("from").split("/")[0]); + .getAttribute("from").split("/",2)[0]); if (muc != null) { boolean before = muc.getMucOptions().online(); muc.getMucOptions().processPacket(packet, mPgpEngine); @@ -32,7 +32,7 @@ public class PresenceParser extends AbstractParser implements } } else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) { Conversation muc = mXmppConnectionService.find(account, packet - .getAttribute("from").split("/")[0]); + .getAttribute("from").split("/",2)[0]); if (muc != null) { boolean before = muc.getMucOptions().online(); muc.getMucOptions().processPacket(packet, mPgpEngine); diff --git a/src/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/eu/siacs/conversations/persistance/DatabaseBackend.java index cda2f356..51fd79e5 100644 --- a/src/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -32,7 +32,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", " + Contact.JID + ") ON CONFLICT REPLACE);"; - public DatabaseBackend(Context context) { + private DatabaseBackend(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @@ -221,6 +221,14 @@ public class DatabaseBackend extends SQLiteOpenHelper { String[] args = { account.getUuid() }; db.delete(Account.TABLENAME, Account.UUID + "=?", args); } + + public boolean hasEnabledAccounts() { + SQLiteDatabase db = this.getReadableDatabase(); + Cursor cursor= db.rawQuery("select count("+Account.UUID+") from "+Account.TABLENAME+" where not options & (1 <<1)", null); + cursor.moveToFirst(); + int count = cursor.getInt(0); + return (count>0); + } @Override public SQLiteDatabase getWritableDatabase() { diff --git a/src/eu/siacs/conversations/services/EventReceiver.java b/src/eu/siacs/conversations/services/EventReceiver.java index c0bf67f3..e2445b2a 100644 --- a/src/eu/siacs/conversations/services/EventReceiver.java +++ b/src/eu/siacs/conversations/services/EventReceiver.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.services; +import eu.siacs.conversations.persistance.DatabaseBackend; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -14,7 +15,9 @@ public class EventReceiver extends BroadcastReceiver { } else { mIntentForService.setAction("other"); } - context.startService(mIntentForService); + if (intent.getAction().equals("ui") || DatabaseBackend.getInstance(context).hasEnabledAccounts()) { + context.startService(mIntentForService); + } } } diff --git a/src/eu/siacs/conversations/services/ImageProvider.java b/src/eu/siacs/conversations/services/ImageProvider.java index 15b86802..af8ab4b2 100644 --- a/src/eu/siacs/conversations/services/ImageProvider.java +++ b/src/eu/siacs/conversations/services/ImageProvider.java @@ -31,7 +31,7 @@ public class ImageProvider extends ContentProvider { if (uuids == null) { throw new FileNotFoundException(); } - String[] uuidsSplited = uuids.split("/"); + String[] uuidsSplited = uuids.split("/",2); if (uuidsSplited.length != 3) { throw new FileNotFoundException(); } diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index c019682e..f80bb9ef 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/eu/siacs/conversations/services/XmppConnectionService.java @@ -96,8 +96,8 @@ public class XmppConnectionService extends Service { private MessageParser mMessageParser = new MessageParser(this); private PresenceParser mPresenceParser = new PresenceParser(this); private IqParser mIqParser = new IqParser(this); - private MessageGenerator mMessageGenerator = new MessageGenerator(); - private PresenceGenerator mPresenceGenerator = new PresenceGenerator(); + private MessageGenerator mMessageGenerator = new MessageGenerator(this); + private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this); private List<Account> accounts; private CopyOnWriteArrayList<Conversation> conversations = null; @@ -585,18 +585,18 @@ public class XmppConnectionService extends Service { } } + conv.getMessages().add(message); + if (!account.getXmppConnection().getFeatures().sm() + && conv.getMode() != Conversation.MODE_MULTI) { + message.setStatus(Message.STATUS_SEND); + } if (saveInDb) { if (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages()) { databaseBackend.createMessage(message); } } - conv.getMessages().add(message); if ((send) && (packet != null)) { - if (!account.getXmppConnection().getFeatures().sm() - && conv.getMode() != Conversation.MODE_MULTI) { - message.setStatus(Message.STATUS_SEND); - } sendMessagePacket(account, packet); } updateConversationUi(); @@ -819,15 +819,15 @@ public class XmppConnectionService extends Service { } }); } - - public List<Message> getMoreMessages(Conversation conversation, - long timestamp) { + + public int loadMoreMessages(Conversation conversation, long timestamp) { List<Message> messages = databaseBackend.getMessages(conversation, 50, timestamp); for (Message message : messages) { message.setConversation(conversation); } - return messages; + conversation.getMessages().addAll(0, messages); + return messages.size(); } public List<Account> getAccounts() { @@ -847,7 +847,7 @@ public class XmppConnectionService extends Service { String jid) { for (Conversation conversation : haystack) { if ((conversation.getAccount().equals(account)) - && (conversation.getContactJid().split("/")[0].equals(jid))) { + && (conversation.getContactJid().split("/",2)[0].equals(jid))) { return conversation; } } @@ -1097,7 +1097,7 @@ public class XmppConnectionService extends Service { } private OnRenameListener renameListener = null; - private IqGenerator mIqGenerator = new IqGenerator(); + private IqGenerator mIqGenerator = new IqGenerator(this); public void setOnRenameListener(OnRenameListener listener) { this.renameListener = listener; @@ -1566,6 +1566,10 @@ public class XmppConnectionService extends Service { return !getPreferences().getBoolean("dont_save_encrypted", false); } + public boolean indicateReceived() { + return getPreferences().getBoolean("indicate_received", false); + } + public void notifyUi(Conversation conversation, boolean notify) { if (mOnConversationUpdate != null) { mOnConversationUpdate.onConversationUpdate(); diff --git a/src/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/eu/siacs/conversations/ui/ChooseContactActivity.java index 277d21d6..62a2cbe1 100644 --- a/src/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -82,6 +82,7 @@ public class ChooseContactActivity extends XmppActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_choose_contact); mListView = (ListView) findViewById(R.id.choose_contact_list); + mListView.setFastScrollEnabled(true); mContactsAdapter = new ListItemAdapter(this, contacts); mListView.setAdapter(mContactsAdapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 2cfa1635..76c12a47 100644 --- a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -201,7 +201,7 @@ public class ConferenceDetailsActivity extends XmppActivity { private void populateView() { mYourPhoto.setImageBitmap(conversation.getAccount().getImage(this, 48)); setTitle(conversation.getName()); - mFullJid.setText(conversation.getContactJid().split("/")[0]); + mFullJid.setText(conversation.getContactJid().split("/",2)[0]); mYourNick.setText(conversation.getMucOptions().getActualNick()); mRoleAffiliaton = (TextView) findViewById(R.id.muc_role); if (conversation.getMucOptions().online()) { diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index 40ad0f33..03d034d9 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -16,7 +16,6 @@ import eu.siacs.conversations.utils.UIHelper; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; -import android.preference.PreferenceManager; import android.provider.MediaStore; import android.app.ActionBar; import android.app.AlertDialog; @@ -791,6 +790,10 @@ public class ConversationActivity extends XmppActivity implements return getPreferences().getBoolean("send_button_status", false); } + public boolean indicateReceived() { + return getPreferences().getBoolean("indicate_received", false); + } + @Override public void onAccountUpdate() { final ConversationFragment fragment = (ConversationFragment) getFragmentManager() diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index e09958cb..299bf281 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -165,14 +165,15 @@ public class ConversationFragment extends Fragment { if (firstVisibleItem == 0 && messagesLoaded) { long timestamp = messageList.get(0).getTimeSent(); messagesLoaded = false; - List<Message> messages = activity.xmppConnectionService - .getMoreMessages(conversation, timestamp); - messageList.addAll(0, messages); + int size = activity.xmppConnectionService.loadMoreMessages( + conversation, timestamp); + messageList.clear(); + messageList.addAll(conversation.getMessages()); messageListAdapter.notifyDataSetChanged(); - if (messages.size() != 0) { + if (size != 0) { messagesLoaded = true; } - messagesView.setSelectionFromTop(messages.size() + 1, 0); + messagesView.setSelectionFromTop(size + 1, 0); } } }; @@ -274,11 +275,23 @@ public class ConversationFragment extends Fragment { @Override public void onContactPictureClicked(Message message) { - if (message.getConversation().getMode() == Conversation.MODE_MULTI) { - if (message.getPresence() != null) { - highlightInConference(message.getPresence()); + if (message.getStatus() <= Message.STATUS_RECEIVED) { + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + if (message.getPresence() != null) { + highlightInConference(message.getPresence()); + } else { + highlightInConference(message + .getCounterpart()); + } } else { - highlightInConference(message.getCounterpart()); + Contact contact = message.getConversation() + .getContact(); + if (contact.showInRoster()) { + activity.switchToContactDetails(contact); + } else { + activity.showAddToRosterDialog(message + .getConversation()); + } } } } @@ -288,11 +301,13 @@ public class ConversationFragment extends Fragment { @Override public void onContactPictureLongClicked(Message message) { - if (message.getConversation().getMode() == Conversation.MODE_MULTI) { - if (message.getPresence() != null) { - privateMessageWith(message.getPresence()); - } else { - privateMessageWith(message.getCounterpart()); + if (message.getStatus() <= Message.STATUS_RECEIVED) { + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + if (message.getPresence() != null) { + privateMessageWith(message.getPresence()); + } else { + privateMessageWith(message.getCounterpart()); + } } } } @@ -492,7 +507,7 @@ public class ConversationFragment extends Fragment { private void messageSent() { int size = this.messageList.size(); - if (size >= 1) { + if (size >= 1 && this.messagesView.getLastVisiblePosition() != size - 1) { messagesView.setSelection(size - 1); } mEditMessage.setText(""); diff --git a/src/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/eu/siacs/conversations/ui/ManageAccountActivity.java index c57121da..ca17eb0d 100644 --- a/src/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -62,7 +62,7 @@ public class ManageAccountActivity extends XmppActivity { @Override public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) { - editAccount(accountList.get(position)); + switchToAccount(accountList.get(position)); } }); registerForContextMenu(accountListView); @@ -163,12 +163,6 @@ public class ManageAccountActivity extends XmppActivity { } } - private void editAccount(Account account) { - Intent intent = new Intent(this, EditAccountActivity.class); - intent.putExtra("jid", account.getJid()); - startActivity(intent); - } - private void publishAvatar(Account account) { Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class); diff --git a/src/eu/siacs/conversations/ui/SettingsActivity.java b/src/eu/siacs/conversations/ui/SettingsActivity.java index 6b280719..fc361fb8 100644 --- a/src/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/eu/siacs/conversations/ui/SettingsActivity.java @@ -1,21 +1,27 @@ package eu.siacs.conversations.ui; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Locale; -import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.os.Build; import android.os.Bundle; +import android.preference.ListPreference; import android.preference.PreferenceManager; public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener { + private SettingsFragment mSettingsFragment; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mSettingsFragment = new SettingsFragment(); getFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment()).commit(); + .replace(android.R.id.content,mSettingsFragment).commit(); } @Override @@ -28,6 +34,13 @@ public class SettingsActivity extends XmppActivity implements super.onStart(); PreferenceManager.getDefaultSharedPreferences(this) .registerOnSharedPreferenceChangeListener(this); + ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource"); + if (resources!=null) { + ArrayList<CharSequence> entries = new ArrayList<CharSequence>(Arrays.asList(resources.getEntries())); + entries.add(0,Build.MODEL); + resources.setEntries(entries.toArray(new CharSequence[entries.size()])); + resources.setEntryValues(entries.toArray(new CharSequence[entries.size()])); + } } @Override diff --git a/src/eu/siacs/conversations/ui/StartConversationActivity.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java index 6287070c..db6c1509 100644 --- a/src/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java @@ -568,6 +568,7 @@ public class StartConversationActivity extends XmppActivity { public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); registerForContextMenu(getListView()); + getListView().setFastScrollEnabled(true); } @Override diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java index 4ee51580..351462ae 100644 --- a/src/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/eu/siacs/conversations/ui/XmppActivity.java @@ -247,6 +247,12 @@ public abstract class XmppActivity extends Activity { intent.putExtra("contact", contact.getJid()); startActivity(intent); } + + public void switchToAccount(Account account) { + Intent intent = new Intent(this, EditAccountActivity.class); + intent.putExtra("jid", account.getJid()); + startActivity(intent); + } protected void inviteToConversation(Conversation conversation) { Intent intent = new Intent(getApplicationContext(), diff --git a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java index db01eabe..035d18c5 100644 --- a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -11,7 +11,6 @@ import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Message; 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.graphics.Bitmap; @@ -97,6 +96,9 @@ public class MessageAdapter extends ArrayAdapter<Message> { String filesize = null; String info = null; boolean error = false; + if (viewHolder.indicatorReceived != null) { + viewHolder.indicatorReceived.setVisibility(View.GONE); + } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI && message.getMergedStatus() <= Message.STATUS_RECEIVED; if (message.getType() == Message.TYPE_IMAGE) { @@ -118,6 +120,16 @@ public class MessageAdapter extends ArrayAdapter<Message> { case Message.STATUS_OFFERED: info = getContext().getString(R.string.offering); break; + case Message.STATUS_SEND_RECEIVED: + if (activity.indicateReceived()) { + viewHolder.indicatorReceived.setVisibility(View.VISIBLE); + } + break; + case Message.STATUS_SEND_DISPLAYED: + if (activity.indicateReceived()) { + viewHolder.indicatorReceived.setVisibility(View.VISIBLE); + } + break; case Message.STATUS_SEND_FAILED: info = getContext().getString(R.string.send_failed); error = true; @@ -129,6 +141,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { case Message.STATUS_RECEPTION_FAILED: info = getContext().getString(R.string.reception_failed); error = true; + break; default: if (multiReceived) { Contact contact = message.getContact(); @@ -155,7 +168,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.indicator.setVisibility(View.VISIBLE); } - String formatedTime = UIHelper.readableTimeDifference(getContext(), + String formatedTime = UIHelper.readableTimeDifferenceFull(getContext(), message.getMergedTimeSent()); if (message.getStatus() <= Message.STATUS_RECEIVED) { if ((filesize != null) && (info != null)) { @@ -337,6 +350,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_body); viewHolder.time = (TextView) view .findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view + .findViewById(R.id.indicator_received); view.setTag(viewHolder); break; case RECEIVED: @@ -406,6 +421,36 @@ public class MessageAdapter extends ArrayAdapter<Message> { return view; } + if (viewHolder.contact_picture != null) { + viewHolder.contact_picture + .setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (MessageAdapter.this.mOnContactPictureClickedListener != null) { + MessageAdapter.this.mOnContactPictureClickedListener + .onContactPictureClicked(item); + ; + } + + } + }); + viewHolder.contact_picture + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { + MessageAdapter.this.mOnContactPictureLongClickedListener + .onContactPictureLongClicked(item); + return true; + } else { + return false; + } + } + }); + } + if (type == RECEIVED) { if (item.getConversation().getMode() == Conversation.MODE_MULTI) { Contact contact = item.getContact(); @@ -420,33 +465,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.contact_picture.setImageBitmap(mBitmapCache.get( name, getContext())); } - viewHolder.contact_picture - .setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (MessageAdapter.this.mOnContactPictureClickedListener != null) { - MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(item); - ; - } - - } - }); - viewHolder.contact_picture - .setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { - MessageAdapter.this.mOnContactPictureLongClickedListener - .onContactPictureLongClicked(item); - return true; - } else { - return false; - } - } - }); } } @@ -512,6 +530,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { protected Button download_button; protected ImageView image; protected ImageView indicator; + protected ImageView indicatorReceived; protected TextView time; protected TextView messageBody; protected ImageView contact_picture; diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java index 54c370ef..f6e66cdb 100644 --- a/src/eu/siacs/conversations/utils/UIHelper.java +++ b/src/eu/siacs/conversations/utils/UIHelper.java @@ -51,10 +51,21 @@ public class UIHelper { private static final int BG_COLOR = 0xFF181818; private static final int FG_COLOR = 0xFFFAFAFA; private static final int TRANSPARENT = 0x00000000; - private static final int DATE_NO_YEAR_FLAGS = DateUtils.FORMAT_SHOW_DATE + private static final int SHORT_DATE_FLAGS = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL; + private static final int FULL_DATE_FLAGS = DateUtils.FORMAT_SHOW_TIME + | DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE; public static String readableTimeDifference(Context context, long time) { + return readableTimeDifference(context, time, false); + } + + public static String readableTimeDifferenceFull(Context context, long time) { + return readableTimeDifference(context, time, true); + } + + private static String readableTimeDifference(Context context, long time, + boolean fullDate) { if (time == 0) { return context.getString(R.string.just_now); } @@ -67,12 +78,17 @@ public class UIHelper { } else if (difference < 60 * 15) { return context.getString(R.string.minutes_ago, Math.round(difference / 60.0)); - } else if (today(date) || difference < 6 * 60 * 60) { + } else if (today(date)) { java.text.DateFormat df = DateFormat.getTimeFormat(context); return df.format(date); } else { - return DateUtils.formatDateTime(context, date.getTime(), - DATE_NO_YEAR_FLAGS); + if (fullDate) { + return DateUtils.formatDateTime(context, date.getTime(), + FULL_DATE_FLAGS); + } else { + return DateUtils.formatDateTime(context, date.getTime(), + SHORT_DATE_FLAGS); + } } } @@ -353,14 +369,15 @@ public class UIHelper { Pattern highlight = generateNickHighlightPattern(nick); Matcher m = highlight.matcher(currentCon.getLatestMessage() .getBody()); - notify = m.find(); + notify = m.find() + || (currentCon.getLatestMessage().getType() == Message.TYPE_PRIVATE); } List<Conversation> unread = new ArrayList<Conversation>(); for (Conversation conversation : conversations) { if (conversation.getMode() == Conversation.MODE_MULTI) { if ((!conversation.isRead()) - && ((wasHighlighted(conversation) || (alwaysNotify)))) { + && ((wasHighlightedOrPrivate(conversation) || (alwaysNotify)))) { unread.add(conversation); } } else { @@ -466,7 +483,7 @@ public class UIHelper { } } - private static boolean wasHighlighted(Conversation conversation) { + private static boolean wasHighlightedOrPrivate(Conversation conversation) { List<Message> messages = conversation.getMessages(); String nick = conversation.getMucOptions().getActualNick(); Pattern highlight = generateNickHighlightPattern(nick); @@ -475,7 +492,8 @@ public class UIHelper { break; } else { Matcher m = highlight.matcher(messages.get(i).getBody()); - if (m.find()) { + if (m.find() + || messages.get(i).getType() == Message.TYPE_PRIVATE) { return true; } } diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java index e7b25e26..e02c772d 100644 --- a/src/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java @@ -657,7 +657,7 @@ public class XmppConnection implements Runnable { if (bind != null) { Element jid = bind.findChild("jid"); if (jid != null) { - account.setResource(jid.getContent().split("/")[1]); + account.setResource(jid.getContent().split("/",2)[1]); if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { smVersion = 3; EnablePacket enable = new EnablePacket(smVersion); diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index f42482e8..4eac99e6 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -256,12 +256,12 @@ public class JingleConnection implements Downloadable { this.status = STATUS_INITIATED; Conversation conversation = this.mXmppConnectionService .findOrCreateConversation(account, - packet.getFrom().split("/")[0], false); + packet.getFrom().split("/",2)[0], false); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); this.message.setType(Message.TYPE_IMAGE); this.message.setStatus(Message.STATUS_RECEIVED_OFFER); this.message.setDownloadable(this); - String[] fromParts = packet.getFrom().split("/"); + String[] fromParts = packet.getFrom().split("/",2); this.message.setPresence(fromParts[1]); this.account = account; this.initiator = packet.getFrom(); |