more cleanup. more listeners

This commit is contained in:
Daniel Gultsch 2014-02-01 15:07:20 +01:00
parent 43531113b7
commit 53d9c9997a
14 changed files with 243 additions and 64 deletions

View File

@ -18,4 +18,8 @@ public abstract class AbstractEntity implements Serializable {
public abstract ContentValues getContentValues(); public abstract ContentValues getContentValues();
public boolean equals(AbstractEntity entity) {
return this.getUuid().equals(entity.getUuid());
}
} }

View File

@ -32,11 +32,13 @@ public class Conversation extends AbstractEntity {
private long created; private long created;
private transient List<Message> messages = null; private transient List<Message> messages = null;
private transient Account account = null;
public Conversation(String name, String profilePhoto, Account account, public Conversation(String name, String profilePhoto, Account account,
String contactJid) { String contactJid) {
this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System this(java.util.UUID.randomUUID().toString(), name, profilePhoto, account.getUuid(), contactJid, System
.currentTimeMillis(), STATUS_AVAILABLE); .currentTimeMillis(), STATUS_AVAILABLE);
this.account = account;
} }
public Conversation(String uuid, String name, String profilePhoto, public Conversation(String uuid, String name, String profilePhoto,
@ -94,6 +96,14 @@ public class Conversation extends AbstractEntity {
return this.accountUuid; return this.accountUuid;
} }
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getContactJid() { public String getContactJid() {
return this.contactJid; return this.contactJid;
} }

View File

@ -40,6 +40,11 @@ public class Message extends AbstractEntity {
this.conversation = conversation; 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, public Message(String uuid, String conversationUUid, String counterpart,
String body, long timeSent, int encryption, int status) { String body, long timeSent, int encryption, int status) {
this.uuid = uuid; this.uuid = uuid;

View File

@ -111,9 +111,9 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return list; return list;
} }
public Conversation findConversation(Account account, Contact contact) { public Conversation findConversation(Account account, String contactJid) {
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = { account.getUuid(), contact.getJid() }; String[] selectionArgs = { account.getUuid(), contactJid };
Cursor cursor = db.query(Conversation.TABLENAME, null, Cursor cursor = db.query(Conversation.TABLENAME, null,
Conversation.ACCOUNT + "=? AND " + Conversation.CONTACT + "=?", Conversation.ACCOUNT + "=? AND " + Conversation.CONTACT + "=?",
selectionArgs, null, null, null); selectionArgs, null, null, null);

View File

@ -1,24 +1,17 @@
package de.gultsch.chat.services; package de.gultsch.chat.services;
import java.io.BufferedInputStream; import java.util.Hashtable;
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.List; 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.Account;
import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Contact;
import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Conversation;
import de.gultsch.chat.entities.Message; import de.gultsch.chat.entities.Message;
import de.gultsch.chat.persistance.DatabaseBackend; import de.gultsch.chat.persistance.DatabaseBackend;
import de.gultsch.chat.xml.Tag; import de.gultsch.chat.ui.OnConversationListChangedListener;
import de.gultsch.chat.xml.XmlReader; import de.gultsch.chat.xmpp.MessagePacket;
import de.gultsch.chat.xmpp.OnMessagePacketReceived;
import de.gultsch.chat.xmpp.XmppConnection; import de.gultsch.chat.xmpp.XmppConnection;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
@ -36,10 +29,32 @@ public class XmppConnectionService extends Service {
public long startDate; public long startDate;
private List<Account> accounts; private List<Account> accounts;
private List<Conversation> conversations = null;
public boolean connectionRunnig = false; private Hashtable<Account,XmppConnection> connections = new Hashtable<Account, XmppConnection>();
private OnConversationListChangedListener convChangedListener = null;
private final IBinder mBinder = new XmppConnectionBinder(); 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 class XmppConnectionBinder extends Binder {
public XmppConnectionService getService() { public XmppConnectionService getService() {
@ -49,16 +64,15 @@ public class XmppConnectionService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { 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); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!connectionRunnig) { for(Account account : accounts) {
for(Account account : accounts) { if (!connections.containsKey(account)) {
Log.d(LOGTAG,"connection wasnt running"); XmppConnection connection = new XmppConnection(account, pm);
XmppConnection connection = new XmppConnection(account, pm); connection.setOnMessagePacketReceivedListener(this.messageListener );
Thread thread = new Thread(connection); Thread thread = new Thread(connection);
thread.start(); thread.start();
} this.connections.put(account, connection);
connectionRunnig = true; }
} }
return START_STICKY; return START_STICKY;
} }
@ -67,7 +81,6 @@ public class XmppConnectionService extends Service {
public void onCreate() { public void onCreate() {
databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
this.accounts = databaseBackend.getAccounts(); this.accounts = databaseBackend.getAccounts();
startDate = System.currentTimeMillis();
} }
@Override @Override
@ -83,8 +96,18 @@ public class XmppConnectionService extends Service {
databaseBackend.createConversation(conversation); databaseBackend.createConversation(conversation);
} }
public List<Conversation> getConversations(int status) { public List<Conversation> getConversations() {
return databaseBackend.getConversations(status); if (this.conversations == null) {
Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
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<Account> getAccounts() { public List<Account> getAccounts() {
@ -96,20 +119,37 @@ public class XmppConnectionService extends Service {
} }
public Conversation findOrCreateConversation(Account account, Contact contact) { 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) { if (conversation!=null) {
Log.d("gultsch","found one. unarchive it"); Log.d("gultsch","found one. unarchive it");
conversation.setStatus(Conversation.STATUS_AVAILABLE); conversation.setStatus(Conversation.STATUS_AVAILABLE);
conversation.setAccount(account);
this.databaseBackend.updateConversation(conversation); this.databaseBackend.updateConversation(conversation);
} else { } else {
Log.d(LOGTAG,"didnt find one in archive. create new one");
conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid()); conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid());
this.databaseBackend.createConversation(conversation); this.databaseBackend.createConversation(conversation);
} }
this.conversations.add(conversation);
if (this.convChangedListener != null) {
this.convChangedListener.onConversationListChanged();
}
return conversation; return conversation;
} }
public void updateConversation(Conversation conversation) { public void archiveConversation(Conversation conversation) {
this.databaseBackend.updateConversation(conversation); this.databaseBackend.updateConversation(conversation);
this.conversations.remove(conversation);
if (this.convChangedListener != null) {
this.convChangedListener.onConversationListChanged();
}
} }
public int getConversationCount() { public int getConversationCount() {
@ -127,4 +167,12 @@ public class XmppConnectionService extends Service {
public void deleteAccount(Account account) { public void deleteAccount(Account account) {
databaseBackend.deleteAccount(account); databaseBackend.deleteAccount(account);
} }
public void setOnConversationListChangedListener(OnConversationListChangedListener listener) {
this.convChangedListener = listener;
}
public void removeOnConversationListChangedListener() {
this.convChangedListener = null;
}
} }

View File

@ -43,6 +43,37 @@ public class ConversationActivity extends XmppActivity {
private ListView listView; private ListView listView;
private boolean paneShouldBeOpen = true; private boolean paneShouldBeOpen = true;
private ArrayAdapter<Conversation> 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<Conversation> getConversationList() { public List<Conversation> getConversationList() {
@ -93,7 +124,7 @@ public class ConversationActivity extends XmppActivity {
listView = (ListView) findViewById(R.id.list); listView = (ListView) findViewById(R.id.list);
listView.setAdapter(new ArrayAdapter<Conversation>(this, this.listAdapter = new ArrayAdapter<Conversation>(this,
R.layout.conversation_list_row, conversationList) { R.layout.conversation_list_row, conversationList) {
@Override @Override
public View getView(int position, View view, ViewGroup parent) { public View getView(int position, View view, ViewGroup parent) {
@ -122,7 +153,9 @@ public class ConversationActivity extends XmppActivity {
return view; return view;
} }
}); };
listView.setAdapter(this.listAdapter);
listView.setOnItemClickListener(new OnItemClickListener() { listView.setOnItemClickListener(new OnItemClickListener() {
@ -212,19 +245,9 @@ public class ConversationActivity extends XmppActivity {
case R.id.action_archive: case R.id.action_archive:
Conversation conv = getConversationList().get(selectedConversation); Conversation conv = getConversationList().get(selectedConversation);
conv.setStatus(Conversation.STATUS_ARCHIVED); conv.setStatus(Conversation.STATUS_ARCHIVED);
xmppConnectionService.updateConversation(conv); paneShouldBeOpen = true;
conversationList.remove(selectedConversation); spl.openPane();
selectedConversation = 0; xmppConnectionService.archiveConversation(conv);
if (conversationList.size() >= 1) {
paneShouldBeOpen = true;
swapConversationFragment();
((ArrayAdapter) listView.getAdapter()).notifyDataSetChanged();
spl.openPane();
} else {
startActivity(new Intent(this, NewConversationActivity.class));
finish();
}
//goto new
break; break;
default: default:
break; break;
@ -259,15 +282,39 @@ public class ConversationActivity extends XmppActivity {
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
conversationList.clear(); conversationList.clear();
conversationList.addAll(xmppConnectionService 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 @Override
void onBackendConnected() { void onBackendConnected() {
xmppConnectionService.setOnConversationListChangedListener(this.onConvChanged);
conversationList.clear(); conversationList.clear();
conversationList.addAll(xmppConnectionService conversationList.addAll(xmppConnectionService
.getConversations(Conversation.STATUS_AVAILABLE)); .getConversations());
for(Conversation conversation : conversationList) { for(Conversation conversation : conversationList) {
conversation.setMessages(xmppConnectionService.getMessages(conversation)); conversation.setMessages(xmppConnectionService.getMessages(conversation));

View File

@ -116,13 +116,16 @@ public class ConversationFragment extends Fragment {
} else { } else {
Log.d("gultsch", "recylecd a view"); Log.d("gultsch", "recylecd a view");
} }
ImageView imageView = (ImageView) view.findViewById(R.id.message_photo);
if (type == RECIEVED) { if (type == RECIEVED) {
((ImageView) view.findViewById(R.id.message_photo)) Uri uri = item.getConversation().getProfilePhotoUri();
.setImageURI(item.getConversation() if (uri!=null) {
.getProfilePhotoUri()); imageView.setImageURI(uri);
} else {
imageView.setImageBitmap(Beautifier.getUnknownContactPicture(item.getConversation().getName(), 200));
}
} else { } else {
((ImageView) view.findViewById(R.id.message_photo)) imageView.setImageURI(profilePicture);
.setImageURI(profilePicture);
} }
((TextView) view.findViewById(R.id.message_body)).setText(item ((TextView) view.findViewById(R.id.message_body)).setText(item
.getBody()); .getBody());

View File

@ -0,0 +1,5 @@
package de.gultsch.chat.ui;
public interface OnConversationListChangedListener {
public void onConversationListChanged();
}

View File

@ -28,6 +28,15 @@ public class Element {
return this; 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) { public boolean hasChild(String name) {
for(Element child : this.children) { for(Element child : this.children) {
if (child.getName().equals(name)) { if (child.getName().equals(name)) {
@ -37,6 +46,10 @@ public class Element {
return false; return false;
} }
public String getContent() {
return content;
}
public Element setAttribute(String name, String value) { public Element setAttribute(String name, String value) {
this.attributes.put(name, value); this.attributes.put(name, value);
return this; return this;

View File

@ -10,4 +10,12 @@ public class MessagePacket extends Element {
public MessagePacket() { public MessagePacket() {
super("message"); super("message");
} }
public String getFrom() {
return getAttribute("from");
}
public String getBody() {
return this.findChild("body").getContent();
}
} }

View File

@ -1,5 +1,7 @@
package de.gultsch.chat.xmpp; package de.gultsch.chat.xmpp;
import de.gultsch.chat.entities.Account;
public interface OnIqPacketReceived { public interface OnIqPacketReceived {
public void onIqPacketReceived(IqPacket packet); public void onIqPacketReceived(Account account, IqPacket packet);
} }

View File

@ -1,5 +1,7 @@
package de.gultsch.chat.xmpp; package de.gultsch.chat.xmpp;
import de.gultsch.chat.entities.Account;
public interface OnMessagePacketReceived { public interface OnMessagePacketReceived {
public void onMessagePacketReceived(MessagePacket packet); public void onMessagePacketReceived(Account account, MessagePacket packet);
} }

View File

@ -1,5 +1,7 @@
package de.gultsch.chat.xmpp; package de.gultsch.chat.xmpp;
import de.gultsch.chat.entities.Account;
public interface OnPresencePacketReceived { public interface OnPresencePacketReceived {
public void onPresencePacketReceived(PresencePacket packet); public void onPresencePacketReceived(Account account, PresencePacket packet);
} }

View File

@ -49,6 +49,9 @@ public class XmppConnection implements Runnable {
private static final int PACKET_PRESENCE = 2; private static final int PACKET_PRESENCE = 2;
private Hashtable<String, OnIqPacketReceived> iqPacketCallbacks = new Hashtable<String, OnIqPacketReceived>(); private Hashtable<String, OnIqPacketReceived> iqPacketCallbacks = new Hashtable<String, OnIqPacketReceived>();
private OnPresencePacketReceived presenceListener = null;
private OnIqPacketReceived unregisteredIqListener = null;
private OnMessagePacketReceived messageListener = null;
public XmppConnection(Account account, PowerManager pm) { public XmppConnection(Account account, PowerManager pm) {
this.account = account; this.account = account;
@ -115,11 +118,11 @@ public class XmppConnection implements Runnable {
sendStartStream(); sendStartStream();
processStream(tagReader.readTag()); processStream(tagReader.readTag());
} else if (nextTag.isStart("iq")) { } else if (nextTag.isStart("iq")) {
Log.d(LOGTAG,processIq(nextTag).toString()); processIq(nextTag);
} else if (nextTag.isStart("message")) { } else if (nextTag.isStart("message")) {
Log.d(LOGTAG,processMessage(nextTag).toString()); processMessage(nextTag);
} else if (nextTag.isStart("presence")) { } else if (nextTag.isStart("presence")) {
Log.d(LOGTAG,processPresence(nextTag).toString()); processPresence(nextTag);
} else { } else {
Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName() Log.d(LOGTAG, "found unexpected tag: " + nextTag.getName()
+ " as child of " + currentTag.getName()); + " as child of " + currentTag.getName());
@ -158,18 +161,26 @@ public class XmppConnection implements Runnable {
private IqPacket processIq(Tag currentTag) throws XmlPullParserException, IOException { private IqPacket processIq(Tag currentTag) throws XmlPullParserException, IOException {
IqPacket packet = (IqPacket) processPacket(currentTag,PACKET_IQ); IqPacket packet = (IqPacket) processPacket(currentTag,PACKET_IQ);
if (iqPacketCallbacks.containsKey(packet.getId())) { if (iqPacketCallbacks.containsKey(packet.getId())) {
iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(packet); iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(account,packet);
iqPacketCallbacks.remove(packet.getId()); iqPacketCallbacks.remove(packet.getId());
} else if (this.unregisteredIqListener != null) {
this.unregisteredIqListener.onIqPacketReceived(account,packet);
} }
return packet; return packet;
} }
private MessagePacket processMessage(Tag currentTag) throws XmlPullParserException, IOException { private void processMessage(Tag currentTag) throws XmlPullParserException, IOException {
return (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE);
if (this.messageListener != null) {
this.messageListener.onMessagePacketReceived(account,packet);
}
} }
private PresencePacket processPresence(Tag currentTag) throws XmlPullParserException, IOException { private void processPresence(Tag currentTag) throws XmlPullParserException, IOException {
return (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE);
if (this.presenceListener != null) {
this.presenceListener.onPresencePacketReceived(account,packet);
}
} }
private void sendStartTLS() throws XmlPullParserException, IOException { private void sendStartTLS() throws XmlPullParserException, IOException {
@ -248,7 +259,7 @@ public class XmppConnection implements Runnable {
iq.addChild(bind); iq.addChild(bind);
this.sendIqPacket(iq, new OnIqPacketReceived() { this.sendIqPacket(iq, new OnIqPacketReceived() {
@Override @Override
public void onIqPacketReceived(IqPacket packet) { public void onIqPacketReceived(Account account, IqPacket packet) {
Log.d(LOGTAG,"answer for our bind was: "+packet.toString()); Log.d(LOGTAG,"answer for our bind was: "+packet.toString());
} }
}); });
@ -277,10 +288,29 @@ public class XmppConnection implements Runnable {
String id = nextRandomId(); String id = nextRandomId();
packet.setAttribute("id",id); packet.setAttribute("id",id);
tagWriter.writeElement(packet); tagWriter.writeElement(packet);
tagWriter.flush();
if (callback != null) { if (callback != null) {
iqPacketCallbacks.put(id, callback); iqPacketCallbacks.put(id, callback);
} }
Log.d(LOGTAG,"sending: "+packet.toString()); 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;
}
} }