package xmpp.client.service;
import java.security.Security;
import java.util.Date;
import org.apache.qpid.management.common.sasl.SaslProvider;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import xmpp.client.Constants;
import xmpp.client.R;
import xmpp.client.account.AccountInfo;
import xmpp.client.service.bookmark.BookmarkService;
import xmpp.client.service.bookmark.BookmarkServiceProvider;
import xmpp.client.service.chat.Chat;
import xmpp.client.service.chat.ChatMessage;
import xmpp.client.service.chat.ChatService;
import xmpp.client.service.chat.ChatServiceProvider;
import xmpp.client.service.chat.ChatSession;
import xmpp.client.service.chat.ParcelableMessage;
import xmpp.client.service.chat.multi.MultiChatMessage;
import xmpp.client.service.chat.single.SingleChatMessage;
import xmpp.client.service.jingle.JingleService;
import xmpp.client.service.user.User;
import xmpp.client.service.user.UserService;
import xmpp.client.service.user.UserServiceProvider;
import xmpp.client.service.user.UserState;
import xmpp.client.service.user.avatar.AvatarService;
import xmpp.client.service.user.avatar.AvatarServiceProvider;
import xmpp.client.service.user.contact.Contact;
import xmpp.client.service.user.contact.ContactList;
import xmpp.client.ui.activities.AppActivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
public class MainService implements Constants, ConnectionProvider,
UserServiceProvider, ChatServiceProvider, BookmarkServiceProvider,
AvatarServiceProvider, ContextProvider {
private static final String TAG = MainService.class.getName();
private final ContextProvider contextProvider;
private final NotificationManager notificationManager;
private final AccountInfo accountInfo;
private BookmarkService bookmarkService;
private AvatarService avatarService;
private JingleService jingleService;
private ChatService chatService;
private UserService userService;
private XMPPConnection connection;
private final MainServiceListener listener;
ConnectionListener connectionListener = new ConnectionListener() {
@Override
public void connectionClosed() {
Log.i(TAG, "connectionClosed");
}
@Override
public void connectionClosedOnError(Exception e) {
Log.i(TAG, "connectionClosedOnError", e);
}
@Override
public void reconnectingIn(int t) {
Log.i(TAG, "reconnectingIn: " + t);
}
@Override
public void reconnectionFailed(Exception e) {
Log.i(TAG, "reconnectionFailed", e);
}
@Override
public void reconnectionSuccessful() {
Log.i(TAG, "reconnectionSuccessful");
}
};
public MainService(MainServiceListener listener,
ContextProvider contextProvider, AccountInfo accountInfo) {
this.listener = listener;
this.accountInfo = accountInfo;
this.contextProvider = contextProvider;
notificationManager = (NotificationManager) getContext()
.getSystemService(Context.NOTIFICATION_SERVICE);
showAccountNotification();
}
public void closeChatSession(ChatSession session) {
chatService.closeChat(session);
}
public boolean connectXMPP() {
if (connection != null) {
if (connection.isConnected()) {
return true;
}
try {
connection.connect();
connection.addConnectionListener(connectionListener);
return true;
} catch (final XMPPException e) {
Log.i(TAG, "connectedXMPP", e);
return false;
}
}
return false;
}
private User createMeUser() {
final User user = new User();
user.setUserLogin(connection.getUser());
user.setRessource(XMPP_RESSOURCE);
user.setUserState(new UserState(UserState.STATUS_AVAILABLE, null));
user.setAvatar(null);
return user;
}
@Override
public AvatarService getAvatarService() {
return avatarService;
}
@Override
public BookmarkService getBookmarkService() {
return bookmarkService;
}
@Override
public ChatService getChatService() {
return chatService;
}
@Override
public XMPPConnection getConnection() {
return connection;
}
public ContactList getContactList() {
return getUserService().getContactList();
}
@Override
public Context getContext() {
return contextProvider.getContext();
}
@Override
public UserService getUserService() {
return userService;
}
public boolean initXMPP() {
if (connection != null) {
connection.disconnect();
}
if (accountInfo == null) {
return false;
}
ConnectionConfiguration config;
if (accountInfo.getPort() == -1) {
config = new ConnectionConfiguration(accountInfo.getHostname());
} else {
config = new ConnectionConfiguration(accountInfo.getHostname(),
accountInfo.getPort());
}
if (accountInfo.getSecurity() == AccountInfo.ACCOUNT_SECURITY_DISABLED) {
config.setSecurityMode(SecurityMode.disabled);
} else if (accountInfo.getSecurity() == AccountInfo.ACCOUNT_SECURITY_ENABLED) {
config.setSecurityMode(SecurityMode.enabled);
} else if (accountInfo.getSecurity() == AccountInfo.ACCOUNT_SECURITY_REQUIRED) {
config.setSecurityMode(SecurityMode.required);
}
config.setReconnectionAllowed(true);
config.setCompressionEnabled(true);
config.setSelfSignedCertificateEnabled(true);
config.setTruststoreType("BKS");
config.setRosterLoadedAtLogin(false);
config.setSendPresence(true);
SmackConfiguration.setKeepAliveInterval(60000);
SmackConfiguration.setPacketReplyTimeout(30000);
connection = new XMPPConnection(config);
return true;
}
public boolean isOnline() {
if (getConnection() != null) {
if (getConnection().isConnected()) {
if (getConnection().isAuthenticated()) {
return true;
}
}
}
return false;
}
public boolean loginXMPP() {
if (connection != null) {
if (connection.isAuthenticated()) {
return true;
}
try {
Security.addProvider(new SaslProvider());
connection.login(accountInfo.getUsername(),
accountInfo.getPassword(), XMPP_RESSOURCE);
connection.getRoster();
avatarService = new AvatarService(this);
bookmarkService = new BookmarkService(this);
userService = new UserService(this, createMeUser());
chatService = new ChatService(this);
jingleService = new JingleService(this);
return true;
} catch (final XMPPException e) {
Log.e(TAG, "loginXMPP", e);
return false;
}
}
return false;
}
public Bundle openChatSession(String uid) {
final Contact contact = getUserService().getContact(uid, false);
final User user = getUserService().getUser(uid, false);
contact.clearUnreadMessages();
ChatSession session = getChatService()
.getChatSessionFromIdentifier(uid);
if (session == null) {
session = getChatService().startSession(user);
}
final Bundle b = new Bundle();
b.putParcelable(FIELD_CHAT_SESSION, session);
b.putParcelable(FIELD_USER, user);
b.putParcelable(FIELD_CONTACT, contact);
return b;
}
public Bundle openMucSession(String muc) {
ChatSession session = getChatService()
.getChatSessionFromIdentifier(muc);
if (session == null) {
session = getChatService().startSession(muc);
}
final Chat chat = getChatService().getChatFromSession(session);
if (!chat.init()) {
closeChatSession(session);
return null;
}
final Bundle b = new Bundle();
b.putParcelable(FIELD_CHAT_SESSION, session);
b.putString(FIELD_SUBJECT, chat.getSubject());
return b;
}
public void processMessage(ChatSession session, ChatMessage chatMessage) {
if (listener.isActiveChatSession(accountInfo, session)) {
if (chatMessage instanceof ParcelableMessage) {
listener.processMessage(accountInfo, session,
(ParcelableMessage) chatMessage);
}
} else {
if (chatMessage instanceof SingleChatMessage) {
showSingleChatNotification((SingleChatMessage) chatMessage);
} else if (chatMessage instanceof MultiChatMessage) {
// TODO Check if contains nickname (highlight) and notify
}
}
}
public boolean sendChatMessage(ChatSession session, String text) {
if (session == null || text == null || text.isEmpty()) {
return false;
} else {
getChatService().sendMessage(session, text);
return true;
}
}
public void sendRosterAdded(User user) {
if (listener.isActiveAccount(accountInfo)) {
listener.sendRosterAdded(accountInfo, user);
}
}
public void sendRosterDeleted(String uid) {
if (listener.isActiveAccount(accountInfo)) {
listener.sendRosterDeleted(accountInfo, uid);
}
}
public void sendRosterUpdated(User user) {
if (user.isMUCUser()) {
getChatService().updateMUCUser(user);
}
if (listener.isActiveAccount(accountInfo)) {
listener.sendRosterUpdated(accountInfo, user);
}
}
public void sendSessionUpdated(ChatSession session) {
if (listener.isActiveChatSession(accountInfo, session)) {
listener.sendSessionUpdated(accountInfo, session);
}
}
private CharSequence shortenCharSequence(CharSequence cs, int chars) {
if (cs.length() > chars) {
return cs.subSequence(0, chars - 1) + "…";
} else {
return cs;
}
}
private void showAccountNotification() {
showNotification(
null,
accountInfo.getFullUsername(),
getUserService() != null ? (String) getUserService()
.getUserMe().getUserState().getStatusText(getContext())
: (String) getContext().getText(
R.string.process_initializing), null, true,
false, 0, R.drawable.stat_base_xmpp, 0, null, new Intent(
getContext(), AppActivity.class), R.string.app_name
+ accountInfo.hashCode());
}
private void showChatNotification(String username, String text,
Bitmap bitmap, int unread, Date date, Intent i) {
showNotification(username + ": " + shortenCharSequence(text, 250),
username, text,
DateFormat.getTimeFormat(getContext()).format(date), false,
false, unread, R.drawable.stat_notify_xmpp,
Notification.DEFAULT_ALL, bitmap, i, R.string.app_name
+ username.hashCode());
}
public void showNotification(String tickerText, String title, String text,
String info, boolean ongoing, boolean autoCancel, int number,
int icon, int notifyDefaults, Bitmap bitmap, Intent intent, int id) {
final Notification.Builder builder = new Notification.Builder(
getContext());
builder.setTicker(tickerText);
builder.setSmallIcon(icon);
builder.setLargeIcon(bitmap);
builder.setDefaults(notifyDefaults);
builder.setAutoCancel(autoCancel);
builder.setNumber(number);
builder.setContentIntent(PendingIntent.getActivity(getContext(), 0,
intent, 0));
builder.setContentTitle(title);
builder.setContentText(text);
builder.setContentInfo(info);
builder.setOngoing(ongoing);
notificationManager.notify(id, builder.getNotification());
}
private void showSingleChatNotification(String username, String login,
String text, Bitmap bitmap, int unread, Date date) {
final Intent i = new Intent(getContext(), AppActivity.class);
i.setData(Uri.parse(URI_SCHEME_IMTO + URI_SCHEME_HOST_DIVIDER
+ URI_HOST_JABBER + URI_PATH_DIVIDER + Uri.encode(login)));
showChatNotification(username, text, bitmap, unread, date, i);
}
private void showSingleChatNotification(
xmpp.client.service.chat.single.SingleChatMessage message) {
final User u = getUserService().getUser(message.getFrom(), false);
final Contact c = getUserService().getContact(u, true);
showSingleChatNotification(u.getDisplayName(), u.getUserLogin(),
message.getText(), u.getBitmap(getContext(), false),
c.getUnreadMessages(), message.getDate());
}
public void updateContact(Contact contact) {
final ContactList contacts = userService.getContactList();
for (final Contact c : contacts) {
if (c.equals(contact)) {
c.setUserContact(contact.getUserContact());
break;
}
}
}
public void updateMeStatus(UserState state) {
final User user = userService.getUserMe();
user.setUserState(state);
showAccountNotification();
if (state.isTemporaryStatus()) {
final Presence presence = state.toPresence();
presence.setFrom(user.getUserLogin() + "/" + XMPP_RESSOURCE);
connection.sendPacket(presence);
}
}
public void updateUser(User user) {
userService.updateUser(user);
}
}