XmppConnectionService.java

  1package de.gultsch.chat.services;
  2
  3import java.io.IOException;
  4import java.util.ArrayList;
  5import java.util.Hashtable;
  6import java.util.List;
  7
  8
  9import de.gultsch.chat.entities.Account;
 10import de.gultsch.chat.entities.Contact;
 11import de.gultsch.chat.entities.Conversation;
 12import de.gultsch.chat.entities.Message;
 13import de.gultsch.chat.persistance.DatabaseBackend;
 14import de.gultsch.chat.ui.OnConversationListChangedListener;
 15import de.gultsch.chat.ui.OnRosterFetchedListener;
 16import de.gultsch.chat.xml.Element;
 17import de.gultsch.chat.xmpp.IqPacket;
 18import de.gultsch.chat.xmpp.MessagePacket;
 19import de.gultsch.chat.xmpp.OnIqPacketReceived;
 20import de.gultsch.chat.xmpp.OnMessagePacketReceived;
 21import de.gultsch.chat.xmpp.XmppConnection;
 22import android.app.Service;
 23import android.content.Context;
 24import android.content.Intent;
 25import android.os.Binder;
 26import android.os.IBinder;
 27import android.os.PowerManager;
 28import android.util.Log;
 29
 30public class XmppConnectionService extends Service {
 31	
 32	protected static final String LOGTAG = "xmppService";
 33	protected DatabaseBackend databaseBackend;
 34	
 35	public long startDate;
 36	
 37	private List<Account> accounts;
 38	private List<Conversation> conversations = null;
 39	
 40	private Hashtable<Account,XmppConnection> connections = new Hashtable<Account, XmppConnection>();
 41
 42	private OnConversationListChangedListener convChangedListener = null;
 43	
 44    private final IBinder mBinder = new XmppConnectionBinder();
 45	private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
 46		
 47		@Override
 48		public void onMessagePacketReceived(Account account, MessagePacket packet) {
 49			String fullJid = packet.getFrom();
 50			String jid = fullJid.split("/")[0];
 51			String name = jid.split("@")[0];
 52			Log.d(LOGTAG,"message received for "+account.getJid()+" from "+jid);
 53			Log.d(LOGTAG,packet.toString());
 54			Contact contact = new Contact(account,name,jid,null); //dummy contact
 55			Conversation conversation = findOrCreateConversation(account, contact);
 56			Message message = new Message(conversation, fullJid, packet.getBody(), Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED);
 57			conversation.getMessages().add(message);
 58			databaseBackend.createMessage(message);
 59			if (convChangedListener != null) {
 60				convChangedListener.onConversationListChanged();
 61			}
 62		}
 63	};
 64
 65    public class XmppConnectionBinder extends Binder {
 66        public XmppConnectionService getService() {
 67        	return XmppConnectionService.this;
 68        }
 69    }
 70    
 71    @Override 
 72    public int onStartCommand(Intent intent, int flags, int startId) {
 73        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
 74        for(Account account : accounts) {
 75        	if (!connections.containsKey(account)) {
 76        		XmppConnection connection = new XmppConnection(account, pm);
 77        		connection.setOnMessagePacketReceivedListener(this.messageListener );
 78        		Thread thread = new Thread(connection);
 79        		thread.start();
 80        		this.connections.put(account, connection);
 81        	}
 82        }
 83        return START_STICKY;
 84    }
 85    
 86    @Override
 87    public void onCreate() {
 88    	databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
 89    	this.accounts = databaseBackend.getAccounts();
 90    }
 91    
 92    @Override
 93    public IBinder onBind(Intent intent) {
 94        return mBinder;
 95    }
 96    
 97    public void sendMessage(final Account account, final Message message) {
 98    	new Thread() {
 99    		@Override
100    		public void run() {
101    			Log.d(LOGTAG,"sending message for "+account.getJid()+" to: "+message.getCounterpart());
102    			databaseBackend.createMessage(message);
103    			MessagePacket packet = new MessagePacket();
104    			packet.setType(MessagePacket.TYPE_CHAT);
105    			packet.setTo(message.getCounterpart());
106    			packet.setFrom(account.getJid());
107    			packet.setBody(message.getBody());
108    			try {
109					connections.get(account).sendMessagePacket(packet);
110					message.setStatus(Message.STATUS_SEND);
111					databaseBackend.updateMessage(message);
112				} catch (IOException e) {
113					Log.d(LOGTAG,"io exception during send. message is in database. will try again later");
114				}
115    		}
116    	}.start();
117    }
118    
119    public void getRoster(final Account account, final OnRosterFetchedListener listener) {
120    	IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
121    	Element query = new Element("query");
122    	query.setAttribute("xmlns", "jabber:iq:roster");
123    	query.setAttribute("ver", "");
124    	iqPacket.addChild(query);
125    	try {
126    		connections.get(account).sendIqPacket(iqPacket, new OnIqPacketReceived() {
127				
128				@Override
129				public void onIqPacketReceived(Account account, IqPacket packet) {
130					Element roster = packet.findChild("query");
131					Log.d(LOGTAG,roster.toString());
132					List<Contact> contacts = new ArrayList<Contact>();
133					for(Element item : roster.getChildren()) {
134						String name = item.getAttribute("name");
135						String jid = item.getAttribute("jid");
136						if (name==null) {
137							name = jid.split("@")[0];
138						}
139						Contact contact = new Contact(account, name, jid, null);
140						contacts.add(contact);
141					}
142					if (listener != null) {
143						listener.onRosterFetched(contacts);
144					}
145				}
146			});
147		} catch (IOException e) {
148			Log.d(LOGTAG,"io error during roster fetch");
149		}
150    }
151    
152    public void addConversation(Conversation conversation) {
153    	databaseBackend.createConversation(conversation);
154    }
155    
156    public List<Conversation> getConversations() {
157    	if (this.conversations == null) {
158	    	Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
159	    	for(Account account : this.accounts) {
160	    		accountLookupTable.put(account.getUuid(), account);
161	    	}
162	    	this.conversations = databaseBackend.getConversations(Conversation.STATUS_AVAILABLE);
163	    	for(Conversation conv : this.conversations) {
164	    		conv.setAccount(accountLookupTable.get(conv.getAccountUuid()));
165	    	}
166    	}
167    	return this.conversations;
168    }
169    
170    public List<Account> getAccounts() {
171    	return this.accounts;
172    }
173    
174    public List<Message> getMessages(Conversation conversation) {
175    	return databaseBackend.getMessages(conversation, 100);
176    }
177
178    public Conversation findOrCreateConversation(Account account, Contact contact) {
179    	Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
180    	for(Conversation conv : this.getConversations()) {
181    		if ((conv.getAccount().equals(account))&&(conv.getContactJid().equals(contact.getJid()))) {
182    			Log.d(LOGTAG,"found one in memory");
183    			return conv;
184    		}
185    	}
186    	Conversation conversation = databaseBackend.findConversation(account, contact.getJid());
187    	if (conversation!=null) {
188    		Log.d("gultsch","found one. unarchive it");
189    		conversation.setStatus(Conversation.STATUS_AVAILABLE);
190    		conversation.setAccount(account);
191    		this.databaseBackend.updateConversation(conversation);
192    	} else {
193    		Log.d(LOGTAG,"didnt find one in archive. create new one");
194    		conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid());
195    		this.databaseBackend.createConversation(conversation);
196    	}
197    	this.conversations.add(conversation);
198    	if (this.convChangedListener != null) {
199    		this.convChangedListener.onConversationListChanged();
200    	}
201    	return conversation;
202    }
203    
204    public void archiveConversation(Conversation conversation) {
205    	this.databaseBackend.updateConversation(conversation);
206    	this.conversations.remove(conversation);
207    	if (this.convChangedListener != null) {
208    		this.convChangedListener.onConversationListChanged();
209    	}
210    }
211    
212    public int getConversationCount() {
213    	return this.databaseBackend.getConversationCount();
214    }
215
216	public void createAccount(Account account) {
217		databaseBackend.createAccount(account);
218	}
219	
220	public void updateAccount(Account account) {
221		databaseBackend.updateAccount(account);
222	}
223
224	public void deleteAccount(Account account) {
225		databaseBackend.deleteAccount(account);
226	}
227	
228	public void setOnConversationListChangedListener(OnConversationListChangedListener listener) {
229		this.convChangedListener = listener;
230	}
231	
232	public void removeOnConversationListChangedListener() {
233		this.convChangedListener = null;
234	}
235}