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				if (!account.isOptionSet(Account.OPTION_DISABLED)) {
 99					this.connections.put(account, this.createConnection(account));
100				} else {
101					Log.d(LOGTAG,account.getJid()+": not starting because it's disabled");
102				}
103			}
104		}
105		return START_STICKY;
106	}
107
108	@Override
109	public void onCreate() {
110		databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
111		this.accounts = databaseBackend.getAccounts();
112	}
113	
114	public XmppConnection createConnection(Account account) {
115		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
116		XmppConnection connection = new XmppConnection(account, pm);
117		connection
118				.setOnMessagePacketReceivedListener(this.messageListener);
119		connection.setOnStatusChangedListener(this.statusListener );
120		Thread thread = new Thread(connection);
121		thread.start();
122		return connection;
123	}
124
125	@Override
126	public IBinder onBind(Intent intent) {
127		return mBinder;
128	}
129
130	public void sendMessage(final Account account, final Message message) {
131		Log.d(LOGTAG, "sending message for " + account.getJid() + " to: "
132				+ message.getCounterpart());
133		databaseBackend.createMessage(message);
134		MessagePacket packet = new MessagePacket();
135		packet.setType(MessagePacket.TYPE_CHAT);
136		packet.setTo(message.getCounterpart());
137		packet.setFrom(account.getJid());
138		packet.setBody(message.getBody());
139		connections.get(account).sendMessagePacket(packet);
140		message.setStatus(Message.STATUS_SEND);
141		databaseBackend.updateMessage(message);
142	}
143
144	public void getRoster(final Account account,
145			final OnRosterFetchedListener listener) {
146		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
147		Element query = new Element("query");
148		query.setAttribute("xmlns", "jabber:iq:roster");
149		query.setAttribute("ver", "");
150		iqPacket.addChild(query);
151		connections.get(account).sendIqPacket(iqPacket,
152				new OnIqPacketReceived() {
153
154					@Override
155					public void onIqPacketReceived(Account account,
156							IqPacket packet) {
157						Element roster = packet.findChild("query");
158						List<Contact> contacts = new ArrayList<Contact>();
159						for (Element item : roster.getChildren()) {
160							String name = item.getAttribute("name");
161							String jid = item.getAttribute("jid");
162							if (name == null) {
163								name = jid.split("@")[0];
164							}
165							Contact contact = new Contact(account, name, jid,
166									null);
167							contacts.add(contact);
168						}
169						if (listener != null) {
170							listener.onRosterFetched(contacts);
171						}
172					}
173				});
174	}
175
176	public void addConversation(Conversation conversation) {
177		databaseBackend.createConversation(conversation);
178	}
179
180	public List<Conversation> getConversations() {
181		if (this.conversations == null) {
182			Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
183			for (Account account : this.accounts) {
184				accountLookupTable.put(account.getUuid(), account);
185			}
186			this.conversations = databaseBackend
187					.getConversations(Conversation.STATUS_AVAILABLE);
188			for (Conversation conv : this.conversations) {
189				conv.setAccount(accountLookupTable.get(conv.getAccountUuid()));
190			}
191		}
192		return this.conversations;
193	}
194
195	public List<Account> getAccounts() {
196		return this.accounts;
197	}
198
199	public List<Message> getMessages(Conversation conversation) {
200		return databaseBackend.getMessages(conversation, 100);
201	}
202
203	public Conversation findOrCreateConversation(Account account,
204			Contact contact) {
205		// Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
206		for (Conversation conv : this.getConversations()) {
207			if ((conv.getAccount().equals(account))
208					&& (conv.getContactJid().equals(contact.getJid()))) {
209				// Log.d(LOGTAG,"found one in memory");
210				return conv;
211			}
212		}
213		Conversation conversation = databaseBackend.findConversation(account,
214				contact.getJid());
215		if (conversation != null) {
216			Log.d("gultsch", "found one. unarchive it");
217			conversation.setStatus(Conversation.STATUS_AVAILABLE);
218			conversation.setAccount(account);
219			this.databaseBackend.updateConversation(conversation);
220		} else {
221			Log.d(LOGTAG, "didnt find one in archive. create new one");
222			conversation = new Conversation(contact.getDisplayName(),
223					contact.getProfilePhoto(), account, contact.getJid());
224			this.databaseBackend.createConversation(conversation);
225		}
226		this.conversations.add(conversation);
227		if (this.convChangedListener != null) {
228			this.convChangedListener.onConversationListChanged();
229		}
230		return conversation;
231	}
232
233	public void archiveConversation(Conversation conversation) {
234		this.databaseBackend.updateConversation(conversation);
235		this.conversations.remove(conversation);
236		if (this.convChangedListener != null) {
237			this.convChangedListener.onConversationListChanged();
238		}
239	}
240
241	public int getConversationCount() {
242		return this.databaseBackend.getConversationCount();
243	}
244
245	public void createAccount(Account account) {
246		databaseBackend.createAccount(account);
247		this.accounts.add(account);
248		this.connections.put(account, this.createConnection(account));
249		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
250	}
251
252	public void updateAccount(Account account) {
253		databaseBackend.updateAccount(account);
254		XmppConnection connection = this.connections.get(account);
255		if (connection != null) {
256			connection.disconnect();
257			this.connections.remove(account);
258		}
259		if (!account.isOptionSet(Account.OPTION_DISABLED)) {
260			this.connections.put(account, this.createConnection(account));
261		} else {
262			Log.d(LOGTAG,account.getJid()+": not starting because it's disabled");
263		}
264		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
265	}
266
267	public void deleteAccount(Account account) {
268		Log.d(LOGTAG,"called delete account");
269		if (this.connections.containsKey(account)) {
270			Log.d(LOGTAG,"found connection. disconnecting");
271			this.connections.get(account).disconnect();
272			this.connections.remove(account);
273			this.accounts.remove(account);
274		}
275		databaseBackend.deleteAccount(account);
276		if (accountChangedListener!=null) accountChangedListener.onAccountListChangedListener();
277	}
278
279	public void setOnConversationListChangedListener(
280			OnConversationListChangedListener listener) {
281		this.convChangedListener = listener;
282	}
283
284	public void removeOnConversationListChangedListener() {
285		this.convChangedListener = null;
286	}
287	
288	public void setOnAccountListChangedListener(OnAccountListChangedListener listener) {
289		this.accountChangedListener = listener;
290	}
291	
292	public void removeOnAccountListChangedListener() {
293		this.accountChangedListener = null;
294	}
295}