From 53d9c9997a508985f0e19aba928bfa25c80ba23e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 1 Feb 2014 15:07:20 +0100 Subject: [PATCH] more cleanup. more listeners --- .../gultsch/chat/entities/AbstractEntity.java | 4 + .../gultsch/chat/entities/Conversation.java | 10 ++ src/de/gultsch/chat/entities/Message.java | 7 +- .../chat/persistance/DatabaseBackend.java | 4 +- .../chat/services/XmppConnectionService.java | 100 +++++++++++++----- .../gultsch/chat/ui/ConversationActivity.java | 81 +++++++++++--- .../gultsch/chat/ui/ConversationFragment.java | 13 ++- .../ui/OnConversationListChangedListener.java | 5 + src/de/gultsch/chat/xml/Element.java | 13 +++ src/de/gultsch/chat/xmpp/MessagePacket.java | 8 ++ .../gultsch/chat/xmpp/OnIqPacketReceived.java | 4 +- .../chat/xmpp/OnMessagePacketReceived.java | 4 +- .../chat/xmpp/OnPresencePacketReceived.java | 4 +- src/de/gultsch/chat/xmpp/XmppConnection.java | 50 +++++++-- 14 files changed, 243 insertions(+), 64 deletions(-) create mode 100644 src/de/gultsch/chat/ui/OnConversationListChangedListener.java diff --git a/src/de/gultsch/chat/entities/AbstractEntity.java b/src/de/gultsch/chat/entities/AbstractEntity.java index d62385a6a..31a19fc0b 100644 --- a/src/de/gultsch/chat/entities/AbstractEntity.java +++ b/src/de/gultsch/chat/entities/AbstractEntity.java @@ -18,4 +18,8 @@ public abstract class AbstractEntity implements Serializable { public abstract ContentValues getContentValues(); + public boolean equals(AbstractEntity entity) { + return this.getUuid().equals(entity.getUuid()); + } + } diff --git a/src/de/gultsch/chat/entities/Conversation.java b/src/de/gultsch/chat/entities/Conversation.java index 10eb70797..ca359477f 100644 --- a/src/de/gultsch/chat/entities/Conversation.java +++ b/src/de/gultsch/chat/entities/Conversation.java @@ -32,11 +32,13 @@ public class Conversation extends AbstractEntity { private long created; private transient List messages = null; + private transient Account account = null; public Conversation(String name, String profilePhoto, Account account, String contactJid) { this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System .currentTimeMillis(), STATUS_AVAILABLE); + this.account = account; } public Conversation(String uuid, String name, String profilePhoto, @@ -93,7 +95,15 @@ public class Conversation extends AbstractEntity { public String getAccountUuid() { return this.accountUuid; } + + public Account getAccount() { + return this.account; + } + public void setAccount(Account account) { + this.account = account; + } + public String getContactJid() { return this.contactJid; } diff --git a/src/de/gultsch/chat/entities/Message.java b/src/de/gultsch/chat/entities/Message.java index 130435b92..530a4db42 100644 --- a/src/de/gultsch/chat/entities/Message.java +++ b/src/de/gultsch/chat/entities/Message.java @@ -39,7 +39,12 @@ public class Message extends AbstractEntity { Message.STATUS_UNSEND); this.conversation = conversation; } - + + public Message(Conversation conversation, String counterpart, String body, int encryption, int status) { + this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),counterpart, body, System.currentTimeMillis(), encryption,status); + this.conversation = conversation; + } + public Message(String uuid, String conversationUUid, String counterpart, String body, long timeSent, int encryption, int status) { this.uuid = uuid; diff --git a/src/de/gultsch/chat/persistance/DatabaseBackend.java b/src/de/gultsch/chat/persistance/DatabaseBackend.java index 85c6df521..10dd0b6e0 100644 --- a/src/de/gultsch/chat/persistance/DatabaseBackend.java +++ b/src/de/gultsch/chat/persistance/DatabaseBackend.java @@ -111,9 +111,9 @@ public class DatabaseBackend extends SQLiteOpenHelper { return list; } - public Conversation findConversation(Account account, Contact contact) { + public Conversation findConversation(Account account, String contactJid) { SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { account.getUuid(), contact.getJid() }; + String[] selectionArgs = { account.getUuid(), contactJid }; Cursor cursor = db.query(Conversation.TABLENAME, null, Conversation.ACCOUNT + "=? AND " + Conversation.CONTACT + "=?", selectionArgs, null, null, null); diff --git a/src/de/gultsch/chat/services/XmppConnectionService.java b/src/de/gultsch/chat/services/XmppConnectionService.java index d078714d1..f2eedbe7e 100644 --- a/src/de/gultsch/chat/services/XmppConnectionService.java +++ b/src/de/gultsch/chat/services/XmppConnectionService.java @@ -1,24 +1,17 @@ package de.gultsch.chat.services; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.UnknownHostException; +import java.util.Hashtable; import java.util.List; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Message; import de.gultsch.chat.persistance.DatabaseBackend; -import de.gultsch.chat.xml.Tag; -import de.gultsch.chat.xml.XmlReader; +import de.gultsch.chat.ui.OnConversationListChangedListener; +import de.gultsch.chat.xmpp.MessagePacket; +import de.gultsch.chat.xmpp.OnMessagePacketReceived; import de.gultsch.chat.xmpp.XmppConnection; import android.app.Service; import android.content.Context; @@ -36,10 +29,32 @@ public class XmppConnectionService extends Service { public long startDate; private List accounts; + private List conversations = null; - public boolean connectionRunnig = false; + private Hashtable connections = new Hashtable(); + private OnConversationListChangedListener convChangedListener = null; + private final IBinder mBinder = new XmppConnectionBinder(); + private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() { + + @Override + public void onMessagePacketReceived(Account account, MessagePacket packet) { + String fullJid = packet.getFrom(); + String jid = fullJid.split("/")[0]; + String name = jid.split("@")[0]; + Log.d(LOGTAG,"message received for "+account.getJid()+" from "+jid); + Log.d(LOGTAG,packet.toString()); + Contact contact = new Contact(name,jid,null); //dummy contact + Conversation conversation = findOrCreateConversation(account, contact); + Message message = new Message(conversation, fullJid, packet.getBody(), Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED); + conversation.getMessages().add(message); + databaseBackend.createMessage(message); + if (convChangedListener != null) { + convChangedListener.onConversationListChanged(); + } + } + }; public class XmppConnectionBinder extends Binder { public XmppConnectionService getService() { @@ -49,16 +64,15 @@ public class XmppConnectionService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(LOGTAG,"recieved start command. been running for "+((System.currentTimeMillis() - startDate) / 1000)+"s"); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - if (!connectionRunnig) { - for(Account account : accounts) { - Log.d(LOGTAG,"connection wasnt running"); - XmppConnection connection = new XmppConnection(account, pm); - Thread thread = new Thread(connection); - thread.start(); - } - connectionRunnig = true; + for(Account account : accounts) { + if (!connections.containsKey(account)) { + XmppConnection connection = new XmppConnection(account, pm); + connection.setOnMessagePacketReceivedListener(this.messageListener ); + Thread thread = new Thread(connection); + thread.start(); + this.connections.put(account, connection); + } } return START_STICKY; } @@ -67,7 +81,6 @@ public class XmppConnectionService extends Service { public void onCreate() { databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); this.accounts = databaseBackend.getAccounts(); - startDate = System.currentTimeMillis(); } @Override @@ -83,8 +96,18 @@ public class XmppConnectionService extends Service { databaseBackend.createConversation(conversation); } - public List getConversations(int status) { - return databaseBackend.getConversations(status); + public List getConversations() { + if (this.conversations == null) { + Hashtable accountLookupTable = new Hashtable(); + for(Account account : this.accounts) { + accountLookupTable.put(account.getUuid(), account); + } + this.conversations = databaseBackend.getConversations(Conversation.STATUS_AVAILABLE); + for(Conversation conv : this.conversations) { + conv.setAccount(accountLookupTable.get(conv.getAccountUuid())); + } + } + return this.conversations; } public List getAccounts() { @@ -96,20 +119,37 @@ public class XmppConnectionService extends Service { } public Conversation findOrCreateConversation(Account account, Contact contact) { - Conversation conversation = databaseBackend.findConversation(account, contact); + Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid()); + for(Conversation conv : this.getConversations()) { + if ((conv.getAccount().equals(account))&&(conv.getContactJid().equals(contact.getJid()))) { + Log.d(LOGTAG,"found one in memory"); + return conv; + } + } + Conversation conversation = databaseBackend.findConversation(account, contact.getJid()); if (conversation!=null) { Log.d("gultsch","found one. unarchive it"); conversation.setStatus(Conversation.STATUS_AVAILABLE); + conversation.setAccount(account); this.databaseBackend.updateConversation(conversation); } else { + Log.d(LOGTAG,"didnt find one in archive. create new one"); conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid()); this.databaseBackend.createConversation(conversation); } + this.conversations.add(conversation); + if (this.convChangedListener != null) { + this.convChangedListener.onConversationListChanged(); + } return conversation; } - public void updateConversation(Conversation conversation) { + public void archiveConversation(Conversation conversation) { this.databaseBackend.updateConversation(conversation); + this.conversations.remove(conversation); + if (this.convChangedListener != null) { + this.convChangedListener.onConversationListChanged(); + } } public int getConversationCount() { @@ -127,4 +167,12 @@ public class XmppConnectionService extends Service { public void deleteAccount(Account account) { databaseBackend.deleteAccount(account); } + + public void setOnConversationListChangedListener(OnConversationListChangedListener listener) { + this.convChangedListener = listener; + } + + public void removeOnConversationListChangedListener() { + this.convChangedListener = null; + } } diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java index 79d1e218f..23d03a015 100644 --- a/src/de/gultsch/chat/ui/ConversationActivity.java +++ b/src/de/gultsch/chat/ui/ConversationActivity.java @@ -43,6 +43,37 @@ public class ConversationActivity extends XmppActivity { private ListView listView; private boolean paneShouldBeOpen = true; + private ArrayAdapter listAdapter; + + private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() { + + @Override + public void onConversationListChanged() { + Log.d("xmppService","on conversation list changed event received"); + conversationList.clear(); + conversationList.addAll(xmppConnectionService + .getConversations()); + runOnUiThread(new Runnable() { + + @Override + public void run() { + listAdapter.notifyDataSetChanged(); + if(paneShouldBeOpen) { + selectedConversation = 0; + if (conversationList.size() >= 1) { + updateConversationList(); + swapConversationFragment(); + } else { + startActivity(new Intent(getApplicationContext(), NewConversationActivity.class)); + finish(); + } + } else { + Log.d("xmppService","pane wasnt open. dont swap fragment"); + } + } + }); + } + }; public List getConversationList() { @@ -93,7 +124,7 @@ public class ConversationActivity extends XmppActivity { listView = (ListView) findViewById(R.id.list); - listView.setAdapter(new ArrayAdapter(this, + this.listAdapter = new ArrayAdapter(this, R.layout.conversation_list_row, conversationList) { @Override public View getView(int position, View view, ViewGroup parent) { @@ -122,7 +153,9 @@ public class ConversationActivity extends XmppActivity { return view; } - }); + }; + + listView.setAdapter(this.listAdapter); listView.setOnItemClickListener(new OnItemClickListener() { @@ -212,19 +245,9 @@ public class ConversationActivity extends XmppActivity { case R.id.action_archive: Conversation conv = getConversationList().get(selectedConversation); conv.setStatus(Conversation.STATUS_ARCHIVED); - xmppConnectionService.updateConversation(conv); - conversationList.remove(selectedConversation); - selectedConversation = 0; - if (conversationList.size() >= 1) { - paneShouldBeOpen = true; - swapConversationFragment(); - ((ArrayAdapter) listView.getAdapter()).notifyDataSetChanged(); - spl.openPane(); - } else { - startActivity(new Intent(this, NewConversationActivity.class)); - finish(); - } - //goto new + paneShouldBeOpen = true; + spl.openPane(); + xmppConnectionService.archiveConversation(conv); break; default: break; @@ -259,15 +282,39 @@ public class ConversationActivity extends XmppActivity { if (xmppConnectionServiceBound) { conversationList.clear(); conversationList.addAll(xmppConnectionService - .getConversations(Conversation.STATUS_AVAILABLE)); + .getConversations()); } } + + @Override + public void onPause() { + super.onPause(); + if (xmppConnectionServiceBound) { + Log.d("xmppService","called on pause. remove listener"); + xmppConnectionService.removeOnConversationListChangedListener(); + } + } + + @Override + protected void onStop() { + super.onStop(); + if (xmppConnectionServiceBound) { + Log.d("xmppService","called on stop. remove listener"); + xmppConnectionService.removeOnConversationListChangedListener(); + unbindService(mConnection); + xmppConnectionServiceBound = false; + } + } + @Override void onBackendConnected() { + + xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged); + conversationList.clear(); conversationList.addAll(xmppConnectionService - .getConversations(Conversation.STATUS_AVAILABLE)); + .getConversations()); for(Conversation conversation : conversationList) { conversation.setMessages(xmppConnectionService.getMessages(conversation)); diff --git a/src/de/gultsch/chat/ui/ConversationFragment.java b/src/de/gultsch/chat/ui/ConversationFragment.java index c3b73ac51..57d4b1ebc 100644 --- a/src/de/gultsch/chat/ui/ConversationFragment.java +++ b/src/de/gultsch/chat/ui/ConversationFragment.java @@ -116,13 +116,16 @@ public class ConversationFragment extends Fragment { } else { Log.d("gultsch", "recylecd a view"); } + ImageView imageView = (ImageView) view.findViewById(R.id.message_photo); if (type == RECIEVED) { - ((ImageView) view.findViewById(R.id.message_photo)) - .setImageURI(item.getConversation() - .getProfilePhotoUri()); + Uri uri = item.getConversation().getProfilePhotoUri(); + if (uri!=null) { + imageView.setImageURI(uri); + } else { + imageView.setImageBitmap(Beautifier.getUnknownContactPicture(item.getConversation().getName(), 200)); + } } else { - ((ImageView) view.findViewById(R.id.message_photo)) - .setImageURI(profilePicture); + imageView.setImageURI(profilePicture); } ((TextView) view.findViewById(R.id.message_body)).setText(item .getBody()); diff --git a/src/de/gultsch/chat/ui/OnConversationListChangedListener.java b/src/de/gultsch/chat/ui/OnConversationListChangedListener.java new file mode 100644 index 000000000..08b2bfb13 --- /dev/null +++ b/src/de/gultsch/chat/ui/OnConversationListChangedListener.java @@ -0,0 +1,5 @@ +package de.gultsch.chat.ui; + +public interface OnConversationListChangedListener { + public void onConversationListChanged(); +} diff --git a/src/de/gultsch/chat/xml/Element.java b/src/de/gultsch/chat/xml/Element.java index af3d8f1ff..24e656491 100644 --- a/src/de/gultsch/chat/xml/Element.java +++ b/src/de/gultsch/chat/xml/Element.java @@ -28,6 +28,15 @@ public class Element { return this; } + public Element findChild(String name) { + for(Element child : this.children) { + if (child.getName().equals(name)) { + return child; + } + } + return null; + } + public boolean hasChild(String name) { for(Element child : this.children) { if (child.getName().equals(name)) { @@ -37,6 +46,10 @@ public class Element { return false; } + public String getContent() { + return content; + } + public Element setAttribute(String name, String value) { this.attributes.put(name, value); return this; diff --git a/src/de/gultsch/chat/xmpp/MessagePacket.java b/src/de/gultsch/chat/xmpp/MessagePacket.java index de6e02347..313fb355b 100644 --- a/src/de/gultsch/chat/xmpp/MessagePacket.java +++ b/src/de/gultsch/chat/xmpp/MessagePacket.java @@ -10,4 +10,12 @@ public class MessagePacket extends Element { public MessagePacket() { super("message"); } + + public String getFrom() { + return getAttribute("from"); + } + + public String getBody() { + return this.findChild("body").getContent(); + } } diff --git a/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java b/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java index 5e69b0cea..0a2e0361d 100644 --- a/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java +++ b/src/de/gultsch/chat/xmpp/OnIqPacketReceived.java @@ -1,5 +1,7 @@ package de.gultsch.chat.xmpp; +import de.gultsch.chat.entities.Account; + public interface OnIqPacketReceived { - public void onIqPacketReceived(IqPacket packet); + public void onIqPacketReceived(Account account, IqPacket packet); } diff --git a/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java b/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java index 9f4e6317b..30f6c29bd 100644 --- a/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java +++ b/src/de/gultsch/chat/xmpp/OnMessagePacketReceived.java @@ -1,5 +1,7 @@ package de.gultsch.chat.xmpp; +import de.gultsch.chat.entities.Account; + public interface OnMessagePacketReceived { - public void onMessagePacketReceived(MessagePacket packet); + public void onMessagePacketReceived(Account account, MessagePacket packet); } diff --git a/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java b/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java index d48c430da..4c9767791 100644 --- a/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java +++ b/src/de/gultsch/chat/xmpp/OnPresencePacketReceived.java @@ -1,5 +1,7 @@ package de.gultsch.chat.xmpp; +import de.gultsch.chat.entities.Account; + public interface OnPresencePacketReceived { - public void onPresencePacketReceived(PresencePacket packet); + public void onPresencePacketReceived(Account account, PresencePacket packet); } diff --git a/src/de/gultsch/chat/xmpp/XmppConnection.java b/src/de/gultsch/chat/xmpp/XmppConnection.java index a167bd87f..441e4b2d3 100644 --- a/src/de/gultsch/chat/xmpp/XmppConnection.java +++ b/src/de/gultsch/chat/xmpp/XmppConnection.java @@ -49,6 +49,9 @@ public class XmppConnection implements Runnable { private static final int PACKET_PRESENCE = 2; private Hashtable iqPacketCallbacks = new Hashtable(); + private OnPresencePacketReceived presenceListener = null; + private OnIqPacketReceived unregisteredIqListener = null; + private OnMessagePacketReceived messageListener = null; public XmppConnection(Account account, PowerManager pm) { this.account = account; @@ -115,11 +118,11 @@ public class XmppConnection implements Runnable { sendStartStream(); processStream(tagReader.readTag()); } else if (nextTag.isStart("iq")) { - Log.d(LOGTAG,processIq(nextTag).toString()); + processIq(nextTag); } else if (nextTag.isStart("message")) { - Log.d(LOGTAG,processMessage(nextTag).toString()); + processMessage(nextTag); } else if (nextTag.isStart("presence")) { - Log.d(LOGTAG,processPresence(nextTag).toString()); + processPresence(nextTag); } else { Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName() + " as child of " + currentTag.getName()); @@ -158,18 +161,26 @@ public class XmppConnection implements Runnable { private IqPacket processIq(Tag currentTag) throws XmlPullParserException, IOException { IqPacket packet = (IqPacket) processPacket(currentTag,PACKET_IQ); if (iqPacketCallbacks.containsKey(packet.getId())) { - iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(packet); + iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(account,packet); iqPacketCallbacks.remove(packet.getId()); + } else if (this.unregisteredIqListener != null) { + this.unregisteredIqListener.onIqPacketReceived(account,packet); } return packet; } - private MessagePacket processMessage(Tag currentTag) throws XmlPullParserException, IOException { - return (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); + private void processMessage(Tag currentTag) throws XmlPullParserException, IOException { + MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); + if (this.messageListener != null) { + this.messageListener.onMessagePacketReceived(account,packet); + } } - private PresencePacket processPresence(Tag currentTag) throws XmlPullParserException, IOException { - return (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); + private void processPresence(Tag currentTag) throws XmlPullParserException, IOException { + PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); + if (this.presenceListener != null) { + this.presenceListener.onPresencePacketReceived(account,packet); + } } private void sendStartTLS() throws XmlPullParserException, IOException { @@ -248,7 +259,7 @@ public class XmppConnection implements Runnable { iq.addChild(bind); this.sendIqPacket(iq, new OnIqPacketReceived() { @Override - public void onIqPacketReceived(IqPacket packet) { + public void onIqPacketReceived(Account account, IqPacket packet) { Log.d(LOGTAG,"answer for our bind was: "+packet.toString()); } }); @@ -277,10 +288,29 @@ public class XmppConnection implements Runnable { String id = nextRandomId(); packet.setAttribute("id",id); tagWriter.writeElement(packet); - tagWriter.flush(); if (callback != null) { iqPacketCallbacks.put(id, callback); } Log.d(LOGTAG,"sending: "+packet.toString()); } + + public void sendMessagePacket(MessagePacket packet) throws IOException { + tagWriter.writeElement(packet); + } + + public void sendPresencePacket(PresencePacket packet) throws IOException { + tagWriter.writeElement(packet); + } + + public void setOnMessagePacketReceivedListener(OnMessagePacketReceived listener) { + this.messageListener = listener; + } + + public void setOnUnregisteredIqPacketReceivedListener(OnIqPacketReceived listener) { + this.unregisteredIqListener = listener; + } + + public void setOnPresencePacketReceivedListener(OnPresencePacketReceived listener) { + this.presenceListener = listener; + } }