Vedroid36
2/5/2013 - 3:14 PM

gistfile1.txt

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;
    }
}