package com.vyke.android.qbchat;
import android.app.Service;
import android.content.*;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.widget.Toast;
import com.quickblox.module.chat.QBChat;
import com.vyke.android.qbchat.dao.ChatDBAdapter;
import com.vyke.android.qbchat.models.Buddy;
import com.vyke.android.qbchat.models.ChatMessage;
import com.vyke.android.qbchat.smack.SmackAndroid;
import com.vyke.android.qbchat.utils.ChatHelper;
import com.vyke.android.qbchat.utils.Lo;
import com.vyke.android.qbchat.utils.NotificationUtils;
import com.vyke.android.utils.Constants;
import com.vyke.android.utils.DataHolder;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.vykesipdroid.sipua.ui.Settings;
import java.util.Collection;
public class ChatService extends Service implements ChatHelper.ContactResult {
private Lo lo = new Lo(this);
public static final String LOG_TAG = "ChatService";
public static final String KEY_PRESENCE_STATUS = "buddy_presence_status";
public static final String KEY_PRESENCE_STATUS_REQUEST = "buddy_presence_status_request";
public static final String KEY_PRESENCE_JID = "buddy_presence_jid";
public static final String EXTRA_KEY_REQUESTER_LIST = "requester_list";
public static final String EXTRA_KEY_REQUESTER = "requester_jid";
public static final String KEY_ACTION_TYPE = "action_type";
public static final int ACTION_TYPE_MESSAGE = 0;
public static final int ACTION_TYPE_PRESENCE = 1;
public static final int ACTION_TYPE_PRESENCE_REQUEST = 1;
public static final String ACTION_CHAT_PACKET_SERVICE = "com.vyke.action.chatPacketService";
public static final String ACTION_CHAT_PACKET_CLIENT = "com.vyke.action.chatPacketClient";
public static final String ACTION_RECEIVE_CHAT_MESSAGE = "com.vyke.action.receiveChatMessage";
public static final String ACTION_SEND_CHAT_MESSAGE = "com.vyke.action.sendChatMessage";
public static final String ACTION_RECEIVE_CHAT_BUDDY = "com.vyke.action.receiveChatBuddy";
public static final String CHAT_SERVER = QBChat.getChatServerDomain();
public static final String FLAG_CHAT_CREATED = "chat_created";
public static final String FLAG_MESSAGE_CREATED = "message_created";
public static boolean isLoginOperationRunning = false;
private XMPPConnection xmppConnection;
private ChatManager chatManager;
private ConnectionConfiguration config;
private Roster roster;
private Chat chat;
protected SharedPreferences preferences;
private NotificationUtils notificationUtils;
private int serviceStartedCounter;
private String shortChatLogin;
private String fullChatLogin;
private String password;
private boolean isNewQBUser;
private Handler handler = new Handler();
private ChatDBAdapter chatDBAdapter;
private ChatHelper chatHelper;
private ChatMessage lastChatMessage;
@Override
public void onCreate() {
super.onCreate();
lo.gt(LOG_TAG, "onCreate");
serviceStartedCounter = 0;
preferences = PreferenceManager.getDefaultSharedPreferences(this);
notificationUtils = new NotificationUtils(getApplicationContext());
chatHelper = new ChatHelper(getApplicationContext());
}
private void init() {
lo.gt(LOG_TAG, "init()");
SmackAndroid.init(getApplicationContext());
IntentFilter intentFilter = new IntentFilter(ACTION_SEND_CHAT_MESSAGE);
registerReceiver(messageFromActivityReceiver, intentFilter);
IntentFilter packetReceivertFilter = new IntentFilter(ChatService.ACTION_CHAT_PACKET_SERVICE);
registerReceiver(packetReceiverService, packetReceivertFilter);
connect();
}
private boolean isNewQBUser() {
lo.gt(LOG_TAG, "isNewQBUser()");
int previousQBUserId = preferences.getInt(Constants.PREF_PREVIOUS_QB_USER_ID, -1);
int currentQBUserId = preferences.getInt(Settings.PREF_QB_USER_ID, -1);
lo.gt(LOG_TAG, ">>>> Previous logged in QB user's id = " + previousQBUserId);
lo.gt(LOG_TAG, ">>>> Current logged in user's QB user id: " + currentQBUserId);
if (currentQBUserId != previousQBUserId || previousQBUserId == -1) return true;
return false;
}
private void getQBChatUserLogin() {
int myQBId = preferences.getInt(Settings.PREF_QB_USER_ID, -1);
password = preferences.getString(Settings.PREF_PASSWORD, "<qb_user_password_error>");
shortChatLogin = QBChat.getChatLoginShort(myQBId);
fullChatLogin = QBChat.getChatLoginFull(myQBId);
lo.gt(LOG_TAG, ">>>> Get QB Chat login (short, full): " + shortChatLogin + ", " + fullChatLogin);
}
private boolean checkNeedReconnect() {
lo.gt(LOG_TAG, "checkNeedReconnect()");
if (xmppConnection == null) return true;
if (xmppConnection.isConnected() == false) return true;
if (xmppConnection.isAuthenticated() == false) return true;
return false;
}
private boolean canStartLogin() {
if (shortChatLogin == null || shortChatLogin.equalsIgnoreCase("-1-1161") == true) return false;
if (xmppConnection == null) return false;
if (xmppConnection.isConnected() == false) return false;
if (isNewQBUser == true) {
return true;
}
if (xmppConnection.isAuthenticated() == true) return false;
return true;
}
private void connect() {
if (isLoginOperationRunning == true){
return;
} else {
isLoginOperationRunning = true;
}
new Thread(new Runnable() {
@Override
public void run() {
Connection.DEBUG_ENABLED = true;
if (config == null) config = new ConnectionConfiguration(CHAT_SERVER);
if (xmppConnection == null) xmppConnection = new XMPPConnection(config);
try {
if (xmppConnection.isConnected() == false) {
lo.gt(LOG_TAG, "Connecting to xmpp server: " + CHAT_SERVER + " ...");
xmppConnection.connect();
} else {
lo.gt(LOG_TAG, "XMPP connection was already established!");
}
lo.gt(LOG_TAG, ">>>> Can we start Login to xmpp server: " + canStartLogin());
if (canStartLogin() == true) {
xmppConnection.login(shortChatLogin, password);
} else {
isLoginOperationRunning = false;
return;
}
lo.gt(LOG_TAG, ">>>> xmppConnection.isAuthenticated() = " + xmppConnection.isAuthenticated());
isLoginOperationRunning = false;
xmppConnection.addConnectionListener(connectionListener);
chatManager = xmppConnection.getChatManager();
chatManager.addChatListener(chatManagerListener);
roster = xmppConnection.getRoster();
DataHolder.getDataHolder().setRoster(roster);
if (roster != null) {
roster.addRosterListener(rosterListener);
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
}
} catch (XMPPException e) {
e.printStackTrace();
lo.gt(LOG_TAG, "XMPPException: " + e.getMessage());
}
}
}).start();
}
private BroadcastReceiver messageFromActivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
lo.gt(LOG_TAG, "<<<< [messageFromActivityReceiver] onReceive");
ChatMessage chatMessage = intent.getExtras().getParcelable(ChatMessage.KEY);
String message = chatMessage.getBody();
String buddyJid = chatMessage.getTo();
sendMessage(buddyJid, message);
if (chatDBAdapter.isDatabaseOpen() == false) {
chatDBAdapter = ChatDBAdapter.getInstance(getApplicationContext());
}
chatDBAdapter.createMessage(chatMessage);
}
};
private void sendMessage(String buddyLogin, String textMessage) {
lo.gt(LOG_TAG, ">>> sendMessage(recipientBuddyJid, textMessage): "+buddyLogin+ ", "+ textMessage);
try {
if (chat == null) {
lo.gt(LOG_TAG, ">>> chat = null, chatManager.createChat(buddyLogin, incomingMessageListener)");
chat = chatManager.createChat(buddyLogin, incomingMessageListener);
} else {
String participant = chat.getParticipant().split("/")[0];
lo.gt(LOG_TAG, ">>> participant, buddyLogin: " + participant + "," + buddyLogin);
if (!participant.equals(buddyLogin)) {
chat = chatManager.createChat(buddyLogin, incomingMessageListener);
}
}
boolean allowSendMessage = xmppConnection.isConnected() && xmppConnection.isAuthenticated();
lo.gt(LOG_TAG, "allow to send message = " + allowSendMessage);
if (allowSendMessage == true) {
chat.sendMessage(textMessage);
} else {
lo.gt(LOG_TAG, "Can't send message, because you are offline.");
handler.post(new Runnable() {
@Override
public void run() {
String messageText = "You need to be online at vyke chat to send messages." +
"Please, try yo login to application one more time.";
Toast.makeText(getApplicationContext(), messageText, Toast.LENGTH_SHORT).show();
}
});
}
} catch (XMPPException e) {
e.printStackTrace();
}
}
private ChatManagerListener chatManagerListener = new ChatManagerListener() {
@Override
public void chatCreated(Chat chat, boolean createdLocally) {
lo.gt(LOG_TAG, ">>>> [ChatManagerListener] chatCreated(Chat): createdLocally = " + createdLocally);
String incomingChatJid = chat.getParticipant().split("/")[0];
Buddy resolvedBuddy = resolveBuddy(incomingChatJid);
chatHelper.synchronizeContact(resolvedBuddy.getJid(), FLAG_CHAT_CREATED);
}
};
private MessageListener incomingMessageListener = new MessageListener() {
@Override
public void processMessage(Chat chat, Message message) {
lo.gt(LOG_TAG, ">>>> Process incoming message(chat, message). Message text: " + message.getBody());
boolean acceptanceFlag = true;
if (message == null || chat == null || message.getBody() == null) {
acceptanceFlag = false;
}
if (acceptanceFlag == false) return;
ChatMessage chatMessage = new ChatMessage(message);
processincomingChatMessage(chatMessage);
}
};
private void processincomingChatMessage(ChatMessage chatMessage) {
lo.gt(LOG_TAG, "processincomingChatMessage(ChatMessage chatMessage): " + chatMessage);
this.lastChatMessage = chatMessage;
chatDBAdapter = ChatDBAdapter.getInstance(getApplicationContext());
chatDBAdapter.createMessage(chatMessage);
Buddy resolvedBuddy = resolveBuddy(chatMessage.getFrom());
chatHelper.synchronizeContact(resolvedBuddy.getJid(), FLAG_MESSAGE_CREATED);
}
private Buddy resolveBuddy(String buddyJid) {
lo.gt(LOG_TAG, ">>>> resolveBuddy(jid): " + buddyJid);
Buddy resolvedBuddy;
if (chatDBAdapter == null || chatDBAdapter.isDatabaseOpen() == false) {
chatDBAdapter = ChatDBAdapter.getInstance(getApplicationContext());
}
resolvedBuddy = chatDBAdapter.fetchBuddyByJid(buddyJid);
lo.gt(LOG_TAG, ">>>> fetchBuddyByJid(jid): " + resolvedBuddy);
if (resolvedBuddy == null) {
resolvedBuddy = new Buddy(buddyJid);
chatDBAdapter.createBuddy(resolvedBuddy);
lo.gt(LOG_TAG, ">>>> chatDBAdapter.createBuddy(resolvedBuddy): " + resolvedBuddy);
}
return resolvedBuddy;
}
@Override
public void onSyncContactError() {
lo.gt(LOG_TAG, "onSyncContactError()");
}
@Override
public void onSyncContactComplete(Buddy buddy, String chatOrMessageCreatedFlag) {
lo.gt(LOG_TAG, ">>>> onSyncContactComplete(buddy, chatOrMessageCreatedFlag): " + buddy + ", " + chatOrMessageCreatedFlag);
if (chatOrMessageCreatedFlag == FLAG_CHAT_CREATED) {
chat.addMessageListener(incomingMessageListener);
try {
roster.createEntry(buddy.getJid(), buddy.getJid(), null);
} catch (XMPPException e) {
e.printStackTrace();
}
Intent incomingBuddyIntent = new Intent();
incomingBuddyIntent.setAction(ACTION_RECEIVE_CHAT_BUDDY);
sendBroadcast(incomingBuddyIntent);
String buddyHumanName = chatHelper.getBuddyHumanReadableName(buddy);
lo.gt(LOG_TAG, "createIncomingChatNotification(buddy, buddyHumanName): "+ buddy + ", " + buddyHumanName);
notificationUtils.createIncomingChatNotification(buddy, buddyHumanName);
} else if (chatOrMessageCreatedFlag == FLAG_MESSAGE_CREATED) {
Intent intent = new Intent();
intent.setAction(ACTION_RECEIVE_CHAT_MESSAGE);
intent.putExtra(KEY_ACTION_TYPE, ACTION_TYPE_MESSAGE);
intent.putExtra(ChatMessage.KEY, this.lastChatMessage);
sendBroadcast(intent);
boolean isNewMessageNotificationRequired = isNewMessageNotificationRequired(buddy.getJid());
lo.gt(LOG_TAG," isNewMessageNotificationRequired: " + isNewMessageNotificationRequired);
if (isNewMessageNotificationRequired == true) {
lo.gt(LOG_TAG, ">>> createMessageNotification(buddy, chatMessageOrNull)s: "+ buddy+ ", " + this.lastChatMessage);
createMessageNotification(buddy, this.lastChatMessage);
}
}
}
private void createMessageNotification(Buddy buddy, ChatMessage chatMessage) {
lo.gt(LOG_TAG, "createMessageNotification");
String buddyHumanName = chatHelper.getBuddyHumanReadableName(buddy);
notificationUtils.createChatMessageNotification(chatMessage, buddy, buddyHumanName);
}
private boolean isNewMessageNotificationRequired(String jid) {
String buddyJidFromPrefs = preferences.getString(Settings.PREF_CURRENT_CHAT_BUDDY_JID, null);
if (buddyJidFromPrefs == null || (buddyJidFromPrefs != null && buddyJidFromPrefs.equals(jid) == false)) {
return true;
}
return false;
}
ConnectionListener connectionListener = new ConnectionListener() {
@Override
public void connectionClosed() {
lo.gt(LOG_TAG, "connectionListener: connectionClosed");
}
@Override
public void connectionClosedOnError(Exception e) {
lo.gt(LOG_TAG, "connectionListener: connectionClosedOnError");
}
@Override
public void reconnectingIn(int i) {
lo.gt(LOG_TAG, "connectionListener: reconnectingIn");
// отстчет времени до рекконекта, период = 60 сек,
// т.е. между рекконектами этот коллбек будет вызван 60 раз.
}
@Override
public void reconnectionSuccessful() {
lo.gt(LOG_TAG, "connectionListener: reconnectionSuccessful");
}
@Override
public void reconnectionFailed(Exception e) {
lo.gt(LOG_TAG, "connectionListener: reconnectionFailed");
}
};
private RosterListener rosterListener = new RosterListener() {
public void entriesDeleted(Collection<String> addresses) {
lo.gt(LOG_TAG, "Roster: entriesDeleted");
}
@Override
public void entriesAdded(Collection<String> strings) {
lo.gt(LOG_TAG, "Roster: entriesAdded");
}
public void entriesUpdated(Collection<String> addresses) {
lo.gt(LOG_TAG, "Roster: entriesUpdated");
}
public void presenceChanged(Presence presence) {
lo.gt(LOG_TAG, "Roster: presenceChanged, from = %s, isAvailable = %s ", presence.getFrom(), presence.isAvailable());
sendPresenceStatus(presence);
}
};
private void sendPresenceStatus(Presence presence) {
lo.gt(LOG_TAG, "sendPresenceStatus(Presence presence)");
Intent intent = new Intent();
intent.setAction(ACTION_CHAT_PACKET_CLIENT);
intent.putExtra(KEY_ACTION_TYPE, ACTION_TYPE_PRESENCE);
intent.putExtra(KEY_PRESENCE_STATUS, presence.isAvailable());
intent.putExtra(KEY_PRESENCE_JID, presence.getFrom().split("/")[0]);
sendBroadcast(intent);
}
private BroadcastReceiver packetReceiverService = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
lo.gt(LOG_TAG, "packetReceiverService: onReceive");
int messageType = intent.getExtras().getInt(KEY_ACTION_TYPE);
if (roster != null) {
switch (messageType) {
case ChatService.ACTION_TYPE_PRESENCE_REQUEST:
// Send chain of requests (for buddy list activity).
String requesterList[] = intent.getExtras().getStringArray(EXTRA_KEY_REQUESTER_LIST);
if (requesterList != null && requesterList.length > 0) {
for (String requester : requesterList) {
Presence p = roster.getPresence(requester);
sendPresenceStatus(p);
}
}
// Send request (for message list activity).
String requesterJid = intent.getExtras().getString(EXTRA_KEY_REQUESTER);
if (requesterJid != null) {
Presence p = roster.getPresence(requesterJid);
sendPresenceStatus(p);
}
break;
}
} else {
lo.gt(LOG_TAG, "Roster is " + roster);
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
lo.gt(LOG_TAG, "onStartCommand, startId = " + startId);
serviceStartedCounter = serviceStartedCounter + 1;
lo.gt(LOG_TAG, ">>>> serviceStartedCounter = " + serviceStartedCounter);
if (serviceStartedCounter == 1) {
isNewQBUser = isNewQBUser();
boolean needReconnect = checkNeedReconnect();
lo.gt(LOG_TAG, ">>>> Do need to re-connect or login to xmpp server: " + needReconnect);
lo.gt(LOG_TAG, ">>>> Is this new QB (and chat) user: " + isNewQBUser);
if (needReconnect == true || isNewQBUser == true) {
getQBChatUserLogin();
init();
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
lo.gt(LOG_TAG, "onDestroy");
unregisterReceiver(messageFromActivityReceiver);
unregisterReceiver(packetReceiverService);
if (chatDBAdapter != null && chatDBAdapter.isDatabaseOpen() == true) {
chatDBAdapter.close();
}
if (xmppConnection != null && xmppConnection.isConnected() == true) {
xmppConnection.disconnect();
}
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}