package xmpp.client.service;
import java.util.HashMap;
import xmpp.client.Constants;
import xmpp.client.account.AccountInfo;
import xmpp.client.service.chat.ChatSession;
import xmpp.client.service.chat.ParcelableMessage;
import xmpp.client.service.chat.multi.MultiChatInfoList;
import xmpp.client.service.handlers.SimpleMessageHandler;
import xmpp.client.service.handlers.SimpleMessageHandlerClient;
import xmpp.client.service.user.User;
import xmpp.client.service.user.UserState;
import xmpp.client.service.user.contact.Contact;
import xmpp.client.service.user.contact.ContactList;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Process;
import android.util.Log;
public class Service extends android.app.Service implements
SimpleMessageHandlerClient, Constants, MainServiceListener,
ContextProvider {
private static final String TAG = Service.class.getName();
private Messenger messenger;
private Messenger activeClient;
private ChatSession activeChatSession;
private AccountInfo activeAccount;
private HashMap<String, MainService> services;
private HandlerThread thread;
private void addUser(Message msg) {
Bundle b = msg.getData();
final String uid = b.getString(FIELD_JID);
final String nick = b.getString(FIELD_NICKNAME);
final User user = getActiveService().getUserService()
.addUser(uid, nick);
if (user != null) {
b = new Bundle();
b.putParcelable(FIELD_USER, user);
sendMsg(msg.replyTo, SIG_ROSTER_ADD, b);
} else {
sendMsg(msg.replyTo, SIG_ROSTER_ADD_ERROR);
}
}
private void closeChatSession(AccountInfo accountInfo, ChatSession session) {
getServiceByAccountInfo(accountInfo).closeChatSession(session);
disableChatSession(session);
}
private void closeChatSession(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
Bundle b = msg.getData();
b.setClassLoader(ChatSession.class.getClassLoader());
final ChatSession session = b.getParcelable(FIELD_CHAT_SESSION);
closeChatSession(accountInfo, session);
b = new Bundle();
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
sendMsg(msg.replyTo, SIG_CLOSE_CHATSESSION, b);
}
private void connect(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
boolean res;
res = connectXMPP(accountInfo);
if (res) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
sendMsg(msg.replyTo, SIG_CONNECT);
} else {
sendMsg(msg.replyTo, SIG_CONNECT_ERROR);
}
}
private boolean connectXMPP(AccountInfo accountInfo) {
return getServiceByAccountInfo(accountInfo).connectXMPP();
}
private void disableChatSession(ChatSession session) {
if (session != null) {
if (session.equals(activeChatSession)) {
activeChatSession = null;
}
}
}
private void disableChatSession(Message msg) {
final Bundle b = msg.getData();
b.setClassLoader(ChatSession.class.getClassLoader());
final ChatSession session = b.getParcelable(FIELD_CHAT_SESSION);
disableChatSession(session);
sendMsg(msg.replyTo, SIG_DISABLE_CHATSESSION);
}
private AccountInfo getAccountInfo(Message msg) {
final Bundle b = msg.getData();
b.setClassLoader(AccountInfo.class.getClassLoader());
AccountInfo accountInfo = b.getParcelable(FIELD_ACCOUNTINFO);
if (accountInfo == null) {
accountInfo = activeAccount;
}
return accountInfo;
}
private MainService getActiveService() {
return getServiceByAccountInfo(activeAccount);
}
private ContactList getContactList(AccountInfo accountInfo) {
return getServiceByAccountInfo(accountInfo).getContactList();
}
private void getContacts(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final ContactList contactList = getContactList(accountInfo);
if (contactList != null) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_CONTACT_LIST, contactList);
sendMsg(msg.replyTo, SIG_ROSTER_GET_CONTACTS, b);
} else {
sendMsg(msg.replyTo, SIG_ROSTER_GET_CONTACTS_ERROR);
}
}
@Override
public Context getContext() {
return this;
}
private MultiChatInfoList getMUCs(AccountInfo accountInfo) {
return getServiceByAccountInfo(accountInfo).getBookmarkService()
.getConferenceHandler().getMultiUserChatInfoList();
}
private void getMUCs(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final Bundle b = new Bundle();
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
b.putParcelable(FIELD_MULTI_USER_CHAT_INFO_LIST, getMUCs(accountInfo));
sendMsg(msg.replyTo, SIG_GET_MUCS, b);
}
private MainService getServiceByAccountInfo(AccountInfo info) {
if (info == null) {
return null;
}
return services.get(info.getFullUsername());
}
private User getUserMe(AccountInfo accountInfo) {
return getServiceByAccountInfo(accountInfo).getUserService()
.getUserMe();
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SIG_OPEN_CHATSESSION:
openChatSession(msg);
break;
case SIG_OPEN_MUC_CHATSESSION:
openMucSession(msg);
break;
case SIG_CLOSE_CHATSESSION:
closeChatSession(msg);
break;
case SIG_SEND_MESSAGE:
sendChatMessage(msg);
break;
case SIG_REGISTER_CLIENT:
register(msg);
break;
case SIG_UNREGISTER_CLIENT:
unregister(msg);
break;
case SIG_INIT:
init(msg);
case SIG_CONNECT:
connect(msg);
case SIG_LOGIN:
login(msg);
break;
case SIG_GET_MUCS:
getMUCs(msg);
break;
case SIG_IS_ONLINE:
isOnline(msg);
break;
case SIG_DISABLE_CHATSESSION:
disableChatSession(msg);
break;
case SIG_SET_STATUS:
updateMeStatus(msg);
break;
case SIG_UPDATE_CONTACT:
updateContact(msg);
break;
case SIG_UPDATE_USER:
updateUser(msg);
break;
case SIG_ROSTER_GET_CONTACTS:
getContacts(msg);
break;
case SIG_ROSTER_ADD:
addUser(msg);
break;
default:
Log.i(TAG, "unknown Message: " + msg.what);
}
}
private void init(Message msg) {
boolean res;
Bundle b;
b = msg.getData();
b.setClassLoader(AccountInfo.class.getClassLoader());
res = initXMPP((AccountInfo) b.getParcelable(FIELD_ACCOUNTINFO));
if (res) {
sendMsg(msg.replyTo, SIG_INIT);
} else {
sendMsg(msg.replyTo, SIG_INIT_ERROR);
}
}
private boolean initXMPP(AccountInfo accountInfo) {
final MainService service = new MainService(this, this, accountInfo);
if (service.initXMPP()) {
services.put(accountInfo.getFullUsername(), service);
activeAccount = accountInfo;
return true;
}
return false;
}
@Override
public boolean isActiveAccount(AccountInfo accountInfo) {
return (activeAccount.equals(accountInfo));
}
@Override
public boolean isActiveChatSession(AccountInfo accountInfo,
ChatSession session) {
return (isActiveAccount(accountInfo) && session
.equals(activeChatSession));
}
private boolean isOnline(AccountInfo accountInfo) {
if (getServiceByAccountInfo(accountInfo) == null) {
return false;
}
return getServiceByAccountInfo(accountInfo).isOnline();
}
private void isOnline(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
boolean res;
res = isOnline(accountInfo);
if (res) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
b.putParcelable(FIELD_USER, getUserMe(accountInfo));
b.putParcelable(FIELD_CONTACT, new Contact(getUserMe(accountInfo)));
sendMsg(msg.replyTo, SIG_IS_ONLINE, b);
} else {
sendMsg(msg.replyTo, SIG_IS_NOT_ONLINE);
}
}
@Override
public boolean isReady() {
return true;
}
private void login(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
boolean res;
res = loginXMPP(accountInfo);
if (res) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
sendMsg(msg.replyTo, SIG_LOGIN);
} else {
sendMsg(msg.replyTo, SIG_LOGIN_ERROR);
}
}
private boolean loginXMPP(AccountInfo accountInfo) {
return getServiceByAccountInfo(accountInfo).loginXMPP();
}
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
@Override
public void onCreate() {
thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.setDaemon(true);
thread.start();
messenger = new Messenger(new SimpleMessageHandler(this,
thread.getLooper()));
services = new HashMap<String, MainService>();
}
@Override
public void onDestroy() {
services = null;
if (thread != null) {
thread.interrupt();
thread = null;
}
activeAccount = null;
if (activeChatSession != null) {
activeChatSession.close();
activeChatSession = null;
}
activeClient = null;
messenger = null;
}
private Bundle openChatSession(AccountInfo accountInfo, String uid) {
return getServiceByAccountInfo(accountInfo).openChatSession(uid);
}
private void openChatSession(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
Bundle b = msg.getData();
final String uid = b.getString(FIELD_JID);
b = openChatSession(accountInfo, uid);
if (accountInfo.equals(activeAccount)) {
b.setClassLoader(ChatSession.class.getClassLoader());
activeChatSession = b.getParcelable(FIELD_CHAT_SESSION);
}
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
sendMsg(msg.replyTo, SIG_OPEN_CHATSESSION, b);
}
private Bundle openMucSession(AccountInfo accountInfo, String muc) {
return getServiceByAccountInfo(accountInfo).openMucSession(muc);
}
private void openMucSession(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
Bundle b = msg.getData();
final String muc = b.getString(FIELD_JID);
b = openMucSession(accountInfo, muc);
if (b != null) {
if (accountInfo.equals(activeAccount)) {
b.setClassLoader(ChatSession.class.getClassLoader());
activeChatSession = b.getParcelable(FIELD_CHAT_SESSION);
}
b.putParcelable(FIELD_ACCOUNTINFO, accountInfo);
sendMsg(msg.replyTo, SIG_OPEN_MUC_CHATSESSION, b);
} else {
sendMsg(msg.replyTo, SIG_OPEN_MUC_CHATSESSION_ERROR);
}
}
@Override
public void processMessage(AccountInfo accountInfo, ChatSession session,
ParcelableMessage chatMessage) {
if (isActiveChatSession(accountInfo, session)) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_CHAT_SESSION, session);
b.putParcelable(FIELD_MESSAGE, chatMessage);
sendToActive(SIG_MESSAGE_GOT, b);
}
}
public void register(Message msg) {
if (msg.replyTo != null) {
if (activeClient != null) {
sendToActive(SIG_UNREGISTER_CLIENT);
disableChatSession(activeChatSession);
}
activeClient = msg.replyTo;
}
}
private boolean sendChatMessage(AccountInfo accountInfo,
ChatSession session, String text) {
return getServiceByAccountInfo(accountInfo).sendChatMessage(session,
text);
}
private void sendChatMessage(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final Bundle b = msg.getData();
b.setClassLoader(ChatSession.class.getClassLoader());
final String text = b.getString(FIELD_TEXT);
final ChatSession session = b.getParcelable(FIELD_CHAT_SESSION);
if (!sendChatMessage(accountInfo, session, text)) {
sendToActive(SIG_SEND_MESSAGE_ERROR);
}
}
private void sendMsg(Messenger m, int msg) {
sendMsg(m, Message.obtain(null, msg));
}
private void sendMsg(Messenger m, int msg, Bundle b) {
final Message message = Message.obtain(null, msg);
message.setData(b);
sendMsg(m, message);
}
private void sendMsg(Messenger m, Message msg) {
try {
m.send(msg);
} catch (final Exception e) {
if (m == activeClient) {
activeClient = null;
disableChatSession(activeChatSession);
}
}
}
@Override
public void sendRosterAdded(AccountInfo accountInfo, User user) {
if (isActiveAccount(accountInfo)) {
final Bundle b = new Bundle();
b.putInt(FIELD_TYPE, ROSTER_ADDED);
b.putString(FIELD_JID, user.getUserLogin());
b.putParcelable(FIELD_USER, user);
sendToActive(SIG_ROSTER_UPDATE, b);
}
}
@Override
public void sendRosterDeleted(AccountInfo accountInfo, String uid) {
if (isActiveAccount(accountInfo)) {
final Bundle b = new Bundle();
b.putInt(FIELD_TYPE, ROSTER_DELETED);
b.putString(FIELD_JID, uid);
sendToActive(SIG_ROSTER_UPDATE, b);
}
}
@Override
public void sendRosterUpdated(AccountInfo accountInfo, User user) {
if (isActiveAccount(accountInfo)) {
final Bundle b = new Bundle();
b.putInt(FIELD_TYPE, ROSTER_UPDATED);
b.putString(FIELD_JID, user.getUserLogin());
b.putParcelable(FIELD_USER, user);
sendToActive(SIG_ROSTER_UPDATE, b);
}
}
@Override
public void sendSessionUpdated(AccountInfo accountInfo, ChatSession session) {
if (isActiveChatSession(accountInfo, session)) {
final Bundle b = new Bundle();
b.putParcelable(FIELD_CHAT_SESSION, session);
sendToActive(SIG_CHAT_SESSION_UPDATE, b);
}
}
private void sendToActive(int msg) {
sendToActive(Message.obtain(null, msg));
}
private void sendToActive(int msg, Bundle b) {
final Message m = Message.obtain(null, msg);
m.setData(b);
sendToActive(m);
}
private void sendToActive(Message msg) {
sendMsg(activeClient, msg);
}
private void unregister(Message msg) {
activeClient = null;
disableChatSession(activeChatSession);
}
private void updateContact(AccountInfo accountInfo, Contact contact) {
getServiceByAccountInfo(accountInfo).updateContact(contact);
}
private void updateContact(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final Bundle b = msg.getData();
b.setClassLoader(Contact.class.getClassLoader());
final Contact contact = b.getParcelable(FIELD_CONTACT);
updateContact(accountInfo, contact);
sendMsg(msg.replyTo, SIG_UPDATE_CONTACT);
}
private void updateMeStatus(AccountInfo accountInfo, UserState state) {
if (getServiceByAccountInfo(accountInfo) == null) {
return;
}
getServiceByAccountInfo(accountInfo).updateMeStatus(state);
}
private void updateMeStatus(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final Bundle b = msg.getData();
b.setClassLoader(UserState.class.getClassLoader());
final UserState state = (UserState) b.getParcelable(FIELD_STATE);
updateMeStatus(accountInfo, state);
}
private void updateUser(AccountInfo accountInfo, User user) {
getServiceByAccountInfo(accountInfo).updateUser(user);
}
private void updateUser(Message msg) {
final AccountInfo accountInfo = getAccountInfo(msg);
final Bundle b = msg.getData();
b.setClassLoader(User.class.getClassLoader());
final User user = b.getParcelable(FIELD_USER);
updateUser(accountInfo, user);
sendMsg(msg.replyTo, SIG_UPDATE_USER);
}
}