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
  8import de.gultsch.chat.entities.Account;
  9import de.gultsch.chat.entities.Contact;
 10import de.gultsch.chat.entities.Conversation;
 11import de.gultsch.chat.entities.Message;
 12import de.gultsch.chat.persistance.DatabaseBackend;
 13import de.gultsch.chat.ui.ConversationActivity;
 14import de.gultsch.chat.ui.OnConversationListChangedListener;
 15import de.gultsch.chat.ui.OnRosterFetchedListener;
 16import de.gultsch.chat.utils.UIHelper;
 17import de.gultsch.chat.xml.Element;
 18import de.gultsch.chat.xmpp.IqPacket;
 19import de.gultsch.chat.xmpp.MessagePacket;
 20import de.gultsch.chat.xmpp.OnIqPacketReceived;
 21import de.gultsch.chat.xmpp.OnMessagePacketReceived;
 22import de.gultsch.chat.xmpp.XmppConnection;
 23import android.R;
 24import android.R.dimen;
 25import android.app.NotificationManager;
 26import android.app.PendingIntent;
 27import android.app.Service;
 28import android.content.Context;
 29import android.content.Intent;
 30import android.content.res.Resources;
 31import android.os.Binder;
 32import android.os.IBinder;
 33import android.os.PowerManager;
 34import android.support.v4.app.NotificationCompat;
 35import android.support.v4.app.TaskStackBuilder;
 36import android.util.Log;
 37
 38public class XmppConnectionService extends Service {
 39
 40	protected static final String LOGTAG = "xmppService";
 41	protected DatabaseBackend databaseBackend;
 42
 43	public long startDate;
 44
 45	private List<Account> accounts;
 46	private List<Conversation> conversations = null;
 47
 48	private Hashtable<Account, XmppConnection> connections = new Hashtable<Account, XmppConnection>();
 49
 50	private OnConversationListChangedListener convChangedListener = null;
 51
 52	private final IBinder mBinder = new XmppConnectionBinder();
 53	private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
 54
 55		@Override
 56		public void onMessagePacketReceived(Account account,
 57				MessagePacket packet) {
 58			if (packet.getType() == MessagePacket.TYPE_CHAT) {
 59				String fullJid = packet.getFrom();
 60				String jid = fullJid.split("/")[0];
 61				String name = jid.split("@")[0];
 62				Contact contact = new Contact(account, name, jid, null); // dummy
 63																			// contact
 64				Conversation conversation = findOrCreateConversation(account,
 65						contact);
 66				Message message = new Message(conversation, fullJid,
 67						packet.getBody(), Message.ENCRYPTION_NONE,
 68						Message.STATUS_RECIEVED);
 69				conversation.getMessages().add(message);
 70				databaseBackend.createMessage(message);
 71				if (convChangedListener != null) {
 72					convChangedListener.onConversationListChanged();
 73				} else {
 74					NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 75					mNotificationManager.notify(2342, UIHelper
 76							.getUnreadMessageNotification(
 77									getApplicationContext(), conversation));
 78				}
 79			}
 80		}
 81	};
 82
 83	public class XmppConnectionBinder extends Binder {
 84		public XmppConnectionService getService() {
 85			return XmppConnectionService.this;
 86		}
 87	}
 88
 89	@Override
 90	public int onStartCommand(Intent intent, int flags, int startId) {
 91		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
 92		for (Account account : accounts) {
 93			if (!connections.containsKey(account)) {
 94				XmppConnection connection = new XmppConnection(account, pm);
 95				connection
 96						.setOnMessagePacketReceivedListener(this.messageListener);
 97				Thread thread = new Thread(connection);
 98				thread.start();
 99				this.connections.put(account, connection);
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	@Override
112	public IBinder onBind(Intent intent) {
113		return mBinder;
114	}
115
116	public void sendMessage(final Account account, final Message message) {
117		new Thread() {
118			@Override
119			public void run() {
120				Log.d(LOGTAG, "sending message for " + account.getJid()
121						+ " to: " + message.getCounterpart());
122				databaseBackend.createMessage(message);
123				MessagePacket packet = new MessagePacket();
124				packet.setType(MessagePacket.TYPE_CHAT);
125				packet.setTo(message.getCounterpart());
126				packet.setFrom(account.getJid());
127				packet.setBody(message.getBody());
128				try {
129					connections.get(account).sendMessagePacket(packet);
130					message.setStatus(Message.STATUS_SEND);
131					databaseBackend.updateMessage(message);
132				} catch (IOException e) {
133					Log.d(LOGTAG,
134							"io exception during send. message is in database. will try again later");
135				}
136			}
137		}.start();
138	}
139
140	public void getRoster(final Account account,
141			final OnRosterFetchedListener listener) {
142		new Thread() {
143			@Override
144			public void run() {
145				IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
146				Element query = new Element("query");
147				query.setAttribute("xmlns", "jabber:iq:roster");
148				query.setAttribute("ver", "");
149				iqPacket.addChild(query);
150				try {
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,
166												name, jid, null);
167										contacts.add(contact);
168									}
169									if (listener != null) {
170										listener.onRosterFetched(contacts);
171									}
172								}
173							});
174				} catch (IOException e) {
175					Log.d(LOGTAG, "io error during roster fetch");
176				}
177			}
178		}.start();
179	}
180
181	public void addConversation(Conversation conversation) {
182		databaseBackend.createConversation(conversation);
183	}
184
185	public List<Conversation> getConversations() {
186		if (this.conversations == null) {
187			Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
188			for (Account account : this.accounts) {
189				accountLookupTable.put(account.getUuid(), account);
190			}
191			this.conversations = databaseBackend
192					.getConversations(Conversation.STATUS_AVAILABLE);
193			for (Conversation conv : this.conversations) {
194				conv.setAccount(accountLookupTable.get(conv.getAccountUuid()));
195			}
196		}
197		return this.conversations;
198	}
199
200	public List<Account> getAccounts() {
201		return this.accounts;
202	}
203
204	public List<Message> getMessages(Conversation conversation) {
205		return databaseBackend.getMessages(conversation, 100);
206	}
207
208	public Conversation findOrCreateConversation(Account account,
209			Contact contact) {
210		// Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid());
211		for (Conversation conv : this.getConversations()) {
212			if ((conv.getAccount().equals(account))
213					&& (conv.getContactJid().equals(contact.getJid()))) {
214				// Log.d(LOGTAG,"found one in memory");
215				return conv;
216			}
217		}
218		Conversation conversation = databaseBackend.findConversation(account,
219				contact.getJid());
220		if (conversation != null) {
221			Log.d("gultsch", "found one. unarchive it");
222			conversation.setStatus(Conversation.STATUS_AVAILABLE);
223			conversation.setAccount(account);
224			this.databaseBackend.updateConversation(conversation);
225		} else {
226			Log.d(LOGTAG, "didnt find one in archive. create new one");
227			conversation = new Conversation(contact.getDisplayName(),
228					contact.getProfilePhoto(), account, contact.getJid());
229			this.databaseBackend.createConversation(conversation);
230		}
231		this.conversations.add(conversation);
232		if (this.convChangedListener != null) {
233			this.convChangedListener.onConversationListChanged();
234		}
235		return conversation;
236	}
237
238	public void archiveConversation(Conversation conversation) {
239		this.databaseBackend.updateConversation(conversation);
240		this.conversations.remove(conversation);
241		if (this.convChangedListener != null) {
242			this.convChangedListener.onConversationListChanged();
243		}
244	}
245
246	public int getConversationCount() {
247		return this.databaseBackend.getConversationCount();
248	}
249
250	public void createAccount(Account account) {
251		databaseBackend.createAccount(account);
252	}
253
254	public void updateAccount(Account account) {
255		databaseBackend.updateAccount(account);
256	}
257
258	public void deleteAccount(Account account) {
259		databaseBackend.deleteAccount(account);
260	}
261
262	public void setOnConversationListChangedListener(
263			OnConversationListChangedListener listener) {
264		this.convChangedListener = listener;
265	}
266
267	public void removeOnConversationListChangedListener() {
268		this.convChangedListener = null;
269	}
270}