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			if (packet.getType()==MessagePacket.TYPE_CHAT) {
 50				Log.d(LOGTAG,account.getJid()+": message of type chat");
 51				String fullJid = packet.getFrom();
 52				String jid = fullJid.split("/")[0];
 53				String name = jid.split("@")[0];
 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
 66    public class XmppConnectionBinder extends Binder {
 67        public XmppConnectionService getService() {
 68        	return XmppConnectionService.this;
 69        }
 70    }
 71    
 72    @Override 
 73    public int onStartCommand(Intent intent, int flags, int startId) {
 74        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
 75        for(Account account : accounts) {
 76        	if (!connections.containsKey(account)) {
 77        		XmppConnection connection = new XmppConnection(account, pm);
 78        		connection.setOnMessagePacketReceivedListener(this.messageListener );
 79        		Thread thread = new Thread(connection);
 80        		thread.start();
 81        		this.connections.put(account, connection);
 82        	}
 83        }
 84        return START_STICKY;
 85    }
 86    
 87    @Override
 88    public void onCreate() {
 89    	databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
 90    	this.accounts = databaseBackend.getAccounts();
 91    }
 92    
 93    @Override
 94    public IBinder onBind(Intent intent) {
 95        return mBinder;
 96    }
 97    
 98    public void sendMessage(final Account account, final Message message) {
 99    	new Thread() {
100    		@Override
101    		public void run() {
102    			Log.d(LOGTAG,"sending message for "+account.getJid()+" to: "+message.getCounterpart());
103    			databaseBackend.createMessage(message);
104    			MessagePacket packet = new MessagePacket();
105    			packet.setType(MessagePacket.TYPE_CHAT);
106    			packet.setTo(message.getCounterpart());
107    			packet.setFrom(account.getJid());
108    			packet.setBody(message.getBody());
109    			try {
110					connections.get(account).sendMessagePacket(packet);
111					message.setStatus(Message.STATUS_SEND);
112					databaseBackend.updateMessage(message);
113				} catch (IOException e) {
114					Log.d(LOGTAG,"io exception during send. message is in database. will try again later");
115				}
116    		}
117    	}.start();
118    }
119    
120    public void getRoster(final Account account, final OnRosterFetchedListener listener) {
121    	new Thread() {
122    		@Override
123    		public void run() {
124    			IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
125    	    	Element query = new Element("query");
126    	    	query.setAttribute("xmlns", "jabber:iq:roster");
127    	    	query.setAttribute("ver", "");
128    	    	iqPacket.addChild(query);
129    	    	try {
130    	    		connections.get(account).sendIqPacket(iqPacket, new OnIqPacketReceived() {
131    					
132    					@Override
133    					public void onIqPacketReceived(Account account, IqPacket packet) {
134    						Element roster = packet.findChild("query");
135    						Log.d(LOGTAG,roster.toString());
136    						List<Contact> contacts = new ArrayList<Contact>();
137    						for(Element item : roster.getChildren()) {
138    							String name = item.getAttribute("name");
139    							String jid = item.getAttribute("jid");
140    							if (name==null) {
141    								name = jid.split("@")[0];
142    							}
143    							Contact contact = new Contact(account, name, jid, null);
144    							contacts.add(contact);
145    						}
146    						if (listener != null) {
147    							listener.onRosterFetched(contacts);
148    						}
149    					}
150    				});
151    			} catch (IOException e) {
152    				Log.d(LOGTAG,"io error during roster fetch");
153    			}
154    		}
155    	}.start();
156    }
157    
158    public void addConversation(Conversation conversation) {
159    	databaseBackend.createConversation(conversation);
160    }
161    
162    public List<Conversation> getConversations() {
163    	if (this.conversations == null) {
164	    	Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
165	    	for(Account account : this.accounts) {
166	    		accountLookupTable.put(account.getUuid(), account);
167	    	}
168	    	this.conversations = databaseBackend.getConversations(Conversation.STATUS_AVAILABLE);
169	    	for(Conversation conv : this.conversations) {
170	    		conv.setAccount(accountLookupTable.get(conv.getAccountUuid()));
171	    	}
172    	}
173    	return this.conversations;
174    }
175    
176    public List<Account> getAccounts() {
177    	return this.accounts;
178    }
179    
180    public List<Message> getMessages(Conversation conversation) {
181    	return databaseBackend.getMessages(conversation, 100);
182    }
183
184    public Conversation findOrCreateConversation(Account account, Contact contact) {
185    	Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
186    	for(Conversation conv : this.getConversations()) {
187    		if ((conv.getAccount().equals(account))&&(conv.getContactJid().equals(contact.getJid()))) {
188    			Log.d(LOGTAG,"found one in memory");
189    			return conv;
190    		}
191    	}
192    	Conversation conversation = databaseBackend.findConversation(account, contact.getJid());
193    	if (conversation!=null) {
194    		Log.d("gultsch","found one. unarchive it");
195    		conversation.setStatus(Conversation.STATUS_AVAILABLE);
196    		conversation.setAccount(account);
197    		this.databaseBackend.updateConversation(conversation);
198    	} else {
199    		Log.d(LOGTAG,"didnt find one in archive. create new one");
200    		conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid());
201    		this.databaseBackend.createConversation(conversation);
202    	}
203    	this.conversations.add(conversation);
204    	if (this.convChangedListener != null) {
205    		this.convChangedListener.onConversationListChanged();
206    	}
207    	return conversation;
208    }
209    
210    public void archiveConversation(Conversation conversation) {
211    	this.databaseBackend.updateConversation(conversation);
212    	this.conversations.remove(conversation);
213    	if (this.convChangedListener != null) {
214    		this.convChangedListener.onConversationListChanged();
215    	}
216    }
217    
218    public int getConversationCount() {
219    	return this.databaseBackend.getConversationCount();
220    }
221
222	public void createAccount(Account account) {
223		databaseBackend.createAccount(account);
224	}
225	
226	public void updateAccount(Account account) {
227		databaseBackend.updateAccount(account);
228	}
229
230	public void deleteAccount(Account account) {
231		databaseBackend.deleteAccount(account);
232	}
233	
234	public void setOnConversationListChangedListener(OnConversationListChangedListener listener) {
235		this.convChangedListener = listener;
236	}
237	
238	public void removeOnConversationListChangedListener() {
239		this.convChangedListener = null;
240	}
241}