XmppConnectionService.java

  1package de.gultsch.chat.services;
  2
  3import java.util.ArrayList;
  4import java.util.Hashtable;
  5import java.util.List;
  6
  7import de.gultsch.chat.entities.Account;
  8import de.gultsch.chat.entities.Contact;
  9import de.gultsch.chat.entities.Conversation;
 10import de.gultsch.chat.entities.Message;
 11import de.gultsch.chat.persistance.DatabaseBackend;
 12import de.gultsch.chat.ui.OnAccountListChangedListener;
 13import de.gultsch.chat.ui.OnConversationListChangedListener;
 14import de.gultsch.chat.ui.OnRosterFetchedListener;
 15import de.gultsch.chat.utils.UIHelper;
 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.OnStatusChanged;
 22import de.gultsch.chat.xmpp.XmppConnection;
 23import android.app.NotificationManager;
 24import android.app.Service;
 25import android.content.Context;
 26import android.content.Intent;
 27import android.os.Binder;
 28import android.os.IBinder;
 29import android.os.PowerManager;
 30import android.util.Log;
 31
 32public class XmppConnectionService extends Service {
 33
 34	protected static final String LOGTAG = "xmppService";
 35	protected DatabaseBackend databaseBackend;
 36
 37	public long startDate;
 38
 39	private List<Account> accounts;
 40	private List<Conversation> conversations = null;
 41
 42	private Hashtable<Account, XmppConnection> connections = new Hashtable<Account, XmppConnection>();
 43
 44	private OnConversationListChangedListener convChangedListener = null;
 45	private OnAccountListChangedListener accountChangedListener = null;
 46
 47	private final IBinder mBinder = new XmppConnectionBinder();
 48	private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
 49
 50		@Override
 51		public void onMessagePacketReceived(Account account,
 52				MessagePacket packet) {
 53			if (packet.getType() == MessagePacket.TYPE_CHAT) {
 54				String fullJid = packet.getFrom();
 55				String jid = fullJid.split("/")[0];
 56				String name = jid.split("@")[0];
 57				Contact contact = new Contact(account, name, jid, null); // dummy
 58																			// contact
 59				Conversation conversation = findOrCreateConversation(account,
 60						contact);
 61				Message message = new Message(conversation, fullJid,
 62						packet.getBody(), Message.ENCRYPTION_NONE,
 63						Message.STATUS_RECIEVED);
 64				conversation.getMessages().add(message);
 65				databaseBackend.createMessage(message);
 66				if (convChangedListener != null) {
 67					convChangedListener.onConversationListChanged();
 68				} else {
 69					NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 70					mNotificationManager.notify(2342, UIHelper
 71							.getUnreadMessageNotification(
 72									getApplicationContext(), conversation));
 73				}
 74			}
 75		}
 76	};
 77	private OnStatusChanged statusListener = new OnStatusChanged() {
 78		
 79		@Override
 80		public void onStatusChanged(Account account) {
 81			Log.d(LOGTAG,account.getJid()+" changed status to "+account.getStatus());
 82			if (accountChangedListener != null) {
 83				accountChangedListener.onAccountListChangedListener();
 84			}
 85		}
 86	};
 87
 88	public class XmppConnectionBinder extends Binder {
 89		public XmppConnectionService getService() {
 90			return XmppConnectionService.this;
 91		}
 92	}
 93
 94	@Override
 95	public int onStartCommand(Intent intent, int flags, int startId) {
 96		for (Account account : accounts) {
 97			if (!connections.containsKey(account)) {
 98				
 99				this.connections.put(account, this.createConnection(account));
100			}
101		}
102		return START_STICKY;
103	}
104
105	@Override
106	public void onCreate() {
107		databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
108		this.accounts = databaseBackend.getAccounts();
109	}
110	
111	public XmppConnection createConnection(Account account) {
112		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
113		XmppConnection connection = new XmppConnection(account, pm);
114		connection
115				.setOnMessagePacketReceivedListener(this.messageListener);
116		connection.setOnStatusChangedListener(this.statusListener );
117		Thread thread = new Thread(connection);
118		thread.start();
119		return connection;
120	}
121
122	@Override
123	public IBinder onBind(Intent intent) {
124		return mBinder;
125	}
126
127	public void sendMessage(final Account account, final Message message) {
128		Log.d(LOGTAG, "sending message for " + account.getJid() + " to: "
129				+ message.getCounterpart());
130		databaseBackend.createMessage(message);
131		MessagePacket packet = new MessagePacket();
132		packet.setType(MessagePacket.TYPE_CHAT);
133		packet.setTo(message.getCounterpart());
134		packet.setFrom(account.getJid());
135		packet.setBody(message.getBody());
136		connections.get(account).sendMessagePacket(packet);
137		message.setStatus(Message.STATUS_SEND);
138		databaseBackend.updateMessage(message);
139	}
140
141	public void getRoster(final Account account,
142			final OnRosterFetchedListener listener) {
143		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
144		Element query = new Element("query");
145		query.setAttribute("xmlns", "jabber:iq:roster");
146		query.setAttribute("ver", "");
147		iqPacket.addChild(query);
148		connections.get(account).sendIqPacket(iqPacket,
149				new OnIqPacketReceived() {
150
151					@Override
152					public void onIqPacketReceived(Account account,
153							IqPacket packet) {
154						Element roster = packet.findChild("query");
155						List<Contact> contacts = new ArrayList<Contact>();
156						for (Element item : roster.getChildren()) {
157							String name = item.getAttribute("name");
158							String jid = item.getAttribute("jid");
159							if (name == null) {
160								name = jid.split("@")[0];
161							}
162							Contact contact = new Contact(account, name, jid,
163									null);
164							contacts.add(contact);
165						}
166						if (listener != null) {
167							listener.onRosterFetched(contacts);
168						}
169					}
170				});
171	}
172
173	public void addConversation(Conversation conversation) {
174		databaseBackend.createConversation(conversation);
175	}
176
177	public List<Conversation> getConversations() {
178		if (this.conversations == null) {
179			Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
180			for (Account account : this.accounts) {
181				accountLookupTable.put(account.getUuid(), account);
182			}
183			this.conversations = databaseBackend
184					.getConversations(Conversation.STATUS_AVAILABLE);
185			for (Conversation conv : this.conversations) {
186				conv.setAccount(accountLookupTable.get(conv.getAccountUuid()));
187			}
188		}
189		return this.conversations;
190	}
191
192	public List<Account> getAccounts() {
193		return this.accounts;
194	}
195
196	public List<Message> getMessages(Conversation conversation) {
197		return databaseBackend.getMessages(conversation, 100);
198	}
199
200	public Conversation findOrCreateConversation(Account account,
201			Contact contact) {
202		// Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
203		for (Conversation conv : this.getConversations()) {
204			if ((conv.getAccount().equals(account))
205					&& (conv.getContactJid().equals(contact.getJid()))) {
206				// Log.d(LOGTAG,"found one in memory");
207				return conv;
208			}
209		}
210		Conversation conversation = databaseBackend.findConversation(account,
211				contact.getJid());
212		if (conversation != null) {
213			Log.d("gultsch", "found one. unarchive it");
214			conversation.setStatus(Conversation.STATUS_AVAILABLE);
215			conversation.setAccount(account);
216			this.databaseBackend.updateConversation(conversation);
217		} else {
218			Log.d(LOGTAG, "didnt find one in archive. create new one");
219			conversation = new Conversation(contact.getDisplayName(),
220					contact.getProfilePhoto(), account, contact.getJid());
221			this.databaseBackend.createConversation(conversation);
222		}
223		this.conversations.add(conversation);
224		if (this.convChangedListener != null) {
225			this.convChangedListener.onConversationListChanged();
226		}
227		return conversation;
228	}
229
230	public void archiveConversation(Conversation conversation) {
231		this.databaseBackend.updateConversation(conversation);
232		this.conversations.remove(conversation);
233		if (this.convChangedListener != null) {
234			this.convChangedListener.onConversationListChanged();
235		}
236	}
237
238	public int getConversationCount() {
239		return this.databaseBackend.getConversationCount();
240	}
241
242	public void createAccount(Account account) {
243		databaseBackend.createAccount(account);
244		this.accounts.add(account);
245		this.connections.put(account, this.createConnection(account));
246		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
247	}
248
249	public void updateAccount(Account account) {
250		databaseBackend.updateAccount(account);
251		XmppConnection connection = this.connections.get(account);
252		if (connection != null) {
253			connection.disconnect();
254			this.connections.remove(account);
255		}
256		this.connections.put(account, this.createConnection(account));
257		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
258	}
259
260	public void deleteAccount(Account account) {
261		Log.d(LOGTAG,"called delete account");
262		if (this.connections.containsKey(account)) {
263			Log.d(LOGTAG,"found connection. disconnecting");
264			this.connections.get(account).disconnect();
265			this.connections.remove(account);
266			this.accounts.remove(account);
267		}
268		databaseBackend.deleteAccount(account);
269		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
270	}
271
272	public void setOnConversationListChangedListener(
273			OnConversationListChangedListener listener) {
274		this.convChangedListener = listener;
275	}
276
277	public void removeOnConversationListChangedListener() {
278		this.convChangedListener = null;
279	}
280	
281	public void setOnAccountListChangedListener(OnAccountListChangedListener listener) {
282		this.accountChangedListener = listener;
283	}
284	
285	public void removeOnAccountListChangedListener() {
286		this.accountChangedListener = null;
287	}
288}